/***********************************************************************\
*                                 vfw.d                                 *
*                                                                       *
*                       Windows API header module                       *
*                 written in the D programming language                 *
*                                                                       *
*                       Placed into public domain                       *
\***********************************************************************/

module win32.vfw;
pragma(lib, "vfw32.lib");

private import
	win32.commdlg,
	win32.wingdi,
	win32.mmsystem,
	win32.unknwn,
	win32.w32api,
	win32.windef,
	win32.winuser;

extern(Windows) {
	DWORD VideoForWindowsVersion();
	LONG InitVFW();
	LONG TermVFW();
}

DWORD MKFOURCC(char ch0, char ch1, char ch2, char ch3) {
	return (cast(DWORD)ch0) | ((cast(DWORD)ch1) << 8) | ((cast(DWORD)ch2) << 16) | ((cast(DWORD)ch3) << 24);
}

/**
 * COMPMAN - Installable Compression Manager.
 */

const ICVERSION = 0x0104;

typedef HANDLE HIC;

const BI_1632 = 0x32333631;

template aviTWOCC(char c0, char c1) {
	const WORD aviTWOCC = c0 | (c1 << 8);
}

const ICTYPE_VIDEO	= mmioFOURCC!('v', 'i', 'd', 'c');
const ICTYPE_AUDIO	= mmioFOURCC!('a', 'u', 'd', 'c');

enum {
	ICERR_OK			= 0,
	ICERR_DONTDRAW		= 1,
	ICERR_NEWPALETTE	= 2,
	ICERR_GOTOKEYFRAME	= 3,
	ICERR_STOPDRAWING	= 4,
}

const ICERR_UNSUPPORTED	= -1;
const ICERR_BADFORMAT	= -2;
const ICERR_MEMORY		= -3;
const ICERR_INTERNAL	= -4;
const ICERR_BADFLAGS	= -5;
const ICERR_BADPARAM	= -6;
const ICERR_BADSIZE		= -7;
const ICERR_BADHANDLE	= -8;
const ICERR_CANTUPDATE	= -9;
const ICERR_ABORT		= -10;
const ICERR_ERROR		= -100;
const ICERR_BADBITDEPTH	= -200;
const ICERR_BADIMAGESIZE = -201;

const ICERR_CUSTOM = -400;

enum {
	ICMODE_COMPRESS			= 1,
	ICMODE_DECOMPRESS,
	ICMODE_FASTDECOMPRESS,
	ICMODE_QUERY,
	ICMODE_FASTCOMPRESS,
	ICMODE_DRAW				= 8,
}

const ICMODE_INTERNALF_FUNCTION32	= 0x8000;
const ICMODE_INTERNALF_MASK			= 0x8000;

enum {
	AVIIF_LIST		= 0x00000001,
	AVIIF_TWOCC		= 0x00000002,
	AVIIF_KEYFRAME	= 0x00000010,
}

const ICQUALITY_LOW		= 0;
const ICQUALITY_HIGH	= 10000;
const ICQUALITY_DEFAULT = -1;

enum {
	ICM_USER			= DRV_USER + 0x0000,
	ICM_RESERVED_LOW	= DRV_USER + 0x1000,
	ICM_RESERVED_HIGH	= DRV_USER + 0x2000,
	ICM_RESERVED		= ICM_RESERVED_LOW,
}

// messages

enum {
	ICM_GETSTATE			= ICM_RESERVED + 0,
	ICM_SETSTATE			= ICM_RESERVED + 1,
	ICM_GETINFO				= ICM_RESERVED + 2,
	ICM_CONFIGURE			= ICM_RESERVED + 10,
	ICM_ABOUT				= ICM_RESERVED + 11,
	ICM_GETERRORTEXT		= ICM_RESERVED + 12,
	ICM_GETFORMATNAME		= ICM_RESERVED + 20,
	ICM_ENUMFORMATS			= ICM_RESERVED + 21,
	ICM_GETDEFAULTQUALITY	= ICM_RESERVED + 30,
	ICM_GETQUALITY			= ICM_RESERVED + 31,
	ICM_SETQUALITY			= ICM_RESERVED + 32,
	ICM_SET					= ICM_RESERVED + 40,
	ICM_GET					= ICM_RESERVED + 41,
}

const ICM_FRAMERATE		= mmioFOURCC!('F','r','m','R');
const ICM_KEYFRAMERATE	= mmioFOURCC!('K','e','y','R');

// ICM specific messages.

enum {
	ICM_COMPRESS_GET_FORMAT		= ICM_USER + 4,
	ICM_COMPRESS_GET_SIZE		= ICM_USER + 5,
	ICM_COMPRESS_QUERY			= ICM_USER + 6,
	ICM_COMPRESS_BEGIN			= ICM_USER + 7,
	ICM_COMPRESS				= ICM_USER + 8,
	ICM_COMPRESS_END			= ICM_USER + 9,
	ICM_DECOMPRESS_GET_FORMAT	= ICM_USER + 10,
	ICM_DECOMPRESS_QUERY		= ICM_USER + 11,
	ICM_DECOMPRESS_BEGIN		= ICM_USER + 12,
	ICM_DECOMPRESS				= ICM_USER + 13,
	ICM_DECOMPRESS_END			= ICM_USER + 14,
	ICM_DECOMPRESS_SET_PALETTE	= ICM_USER + 29,
	ICM_DECOMPRESS_GET_PALETTE	= ICM_USER + 30,
	ICM_DRAW_QUERY				= ICM_USER + 31,
	ICM_DRAW_BEGIN				= ICM_USER + 15,
	ICM_DRAW_GET_PALETTE		= ICM_USER + 16,
	ICM_DRAW_UPDATE				= ICM_USER + 17,
	ICM_DRAW_START				= ICM_USER + 18,
	ICM_DRAW_STOP				= ICM_USER + 19,
	ICM_DRAW_BITS				= ICM_USER + 20,
	ICM_DRAW_END				= ICM_USER + 21,
	ICM_DRAW_GETTIME			= ICM_USER + 32,
	ICM_DRAW					= ICM_USER + 33,
	ICM_DRAW_WINDOW				= ICM_USER + 34,
	ICM_DRAW_SETTIME			= ICM_USER + 35,
	ICM_DRAW_REALIZE			= ICM_USER + 36,
	ICM_DRAW_FLUSH				= ICM_USER + 37,
	ICM_DRAW_RENDERBUFFER		= ICM_USER + 38,
	ICM_DRAW_START_PLAY			= ICM_USER + 39,
	ICM_DRAW_STOP_PLAY			= ICM_USER + 40,
	ICM_DRAW_SUGGESTFORMAT		= ICM_USER + 50,
	ICM_DRAW_CHANGEPALETTE		= ICM_USER + 51,
	ICM_DRAW_IDLE				= ICM_USER + 52,
	ICM_GETBUFFERSWANTED		= ICM_USER + 41,
	ICM_GETDEFAULTKEYFRAMERATE	= ICM_USER + 42,
	ICM_DECOMPRESSEX_BEGIN		= ICM_USER + 60,
	ICM_DECOMPRESSEX_QUERY		= ICM_USER + 61,
	ICM_DECOMPRESSEX			= ICM_USER + 62,
	ICM_DECOMPRESSEX_END		= ICM_USER + 63,
	ICM_COMPRESS_FRAMES_INFO	= ICM_USER + 70,
	ICM_COMPRESS_FRAMES			= ICM_USER + 71,
	ICM_SET_STATUS_PROC			= ICM_USER + 72,
}

struct ICOPEN {
	DWORD	dwSize;
	DWORD	fccType;
	DWORD	fccHandler;
	DWORD	dwVersion;
	DWORD	dwFlags;
	LRESULT	dwError;
	LPVOID	pV1Reserved;
	LPVOID	pV2Reserved;
	DWORD	dnDevNode;
}

struct ICINFO {
	DWORD	dwSize;
	DWORD	fccType;
	DWORD	fccHandler;
	DWORD	dwFlags;
	DWORD	dwVersion;
	DWORD	dwVersionICM;
	WCHAR	szName[16];
	WCHAR	szDescription[128];
	WCHAR	szDriver[128];
}

enum {
	VIDCF_QUALITY			= 0x0001,
	VIDCF_CRUNCH			= 0x0002,
	VIDCF_TEMPORAL			= 0x0004,
	VIDCF_COMPRESSFRAMES	= 0x0008,
	VIDCF_DRAW				= 0x0010,
	VIDCF_FASTTEMPORALC		= 0x0020,
	VIDCF_FASTTEMPORALD		= 0x0080,
}

const ICCOMPRESS_KEYFRAME = 0x00000001L;

struct ICCOMPRESS {
	DWORD				dwFlags;
	LPBITMAPINFOHEADER	lpbiOutput;
	LPVOID				lpOutput;
	LPBITMAPINFOHEADER	lpbiInput;
	LPVOID				lpInput;
	LPDWORD				lpckid;
	LPDWORD				lpdwFlags;
	LONG				lFrameNum;
	DWORD				dwFrameSize;
	DWORD				dwQuality;
	LPBITMAPINFOHEADER	lpbiPrev;
	LPVOID				lpPrev;
}

const ICCOMPRESSFRAMES_PADDING = 0x00000001;

struct ICCOMPRESSFRAMES {
	DWORD				dwFlags;
	LPBITMAPINFOHEADER	lpbiOutput;
	LPARAM				lOutput;
	LPBITMAPINFOHEADER	lpbiInput;
	LPARAM				lInput;
	LONG				lStartFrame;
	LONG				lFrameCount;
	LONG				lQuality;
	LONG				lDataRate;
	LONG				lKeyRate;
	DWORD				dwRate;
	DWORD				dwScale;    DWORD		dwOverheadPerFrame;
	DWORD				dwReserved2;

	LONG function(LPARAM lInput, LONG lFrame, LPVOID lpBits, LONG len) GetData;
	LONG function(LPARAM lOutput, LONG lFrame, LPVOID lpBits, LONG len) PutData;
}

enum {
	ICSTATUS_START	= 0,
	ICSTATUS_STATUS	= 1,
	ICSTATUS_END	= 2,
	ICSTATUS_ERROR	= 3,
	ICSTATUS_YIELD	= 4,
}

struct ICSETSTATUSPROC {
	DWORD	dwFlags;
	LPARAM	lParam;
	LONG function(LPARAM lParam, UINT message, LONG l) Status;
}

enum {
	ICDECOMPRESS_NOTKEYFRAME	= 0x08000000,
	ICDECOMPRESS_NULLFRAME		= 0x10000000,
	ICDECOMPRESS_PREROLL		= 0x20000000,
	ICDECOMPRESS_UPDATE			= 0x40000000,
	ICDECOMPRESS_HURRYUP		= 0x80000000,
}

struct ICDECOMPRESS {
	DWORD				dwFlags;
	LPBITMAPINFOHEADER	lpbiInput;
	LPVOID				lpInput;
	LPBITMAPINFOHEADER	lpbiOutput;
	LPVOID				lpOutput;
	DWORD				ckid;
}

struct ICDECOMPRESSEX {
	DWORD				dwFlags;
	LPBITMAPINFOHEADER  lpbiSrc;
	LPVOID				lpSrc;
	LPBITMAPINFOHEADER	lpbiDst;
	LPVOID				lpDst;
	int					xDst;
	int					yDst;
	int					dxDst;
	int					dyDst;
	int					xSrc;
	int					ySrc;
	int					dxSrc;
	int					dySrc;
}

enum {
	ICDRAW_QUERY		= 0x00000001,
	ICDRAW_FULLSCREEN	= 0x00000002,
	ICDRAW_HDC			= 0x00000004,
	ICDRAW_ANIMATE		= 0x00000008,
	ICDRAW_CONTINUE		= 0x00000010,
	ICDRAW_MEMORYDC		= 0x00000020,
	ICDRAW_UPDATING		= 0x00000040,
	ICDRAW_RENDER		= 0x00000080,
	ICDRAW_BUFFER		= 0x00000100,
}

struct ICDRAWBEGIN {
	DWORD				dwFlags;
	HPALETTE			hpal;
	HWND				hwnd;
	HDC					hdc;
	int					xDst;
	int					yDst;
	int					dxDst;
	int					dyDst;
	LPBITMAPINFOHEADER	lpbi;
	int					xSrc;
	int					ySrc;
	int					dxSrc;
	int					dySrc;
	DWORD				dwRate;
	DWORD				dwScale;
}

enum {
	ICDRAW_NOTKEYFRAME	= 0x08000000,
	ICDRAW_NULLFRAME	= 0x10000000,
	ICDRAW_PREROLL		= 0x20000000,
	ICDRAW_UPDATE		= 0x40000000,
	ICDRAW_HURRYUP		= 0x80000000,
}

struct ICDRAW {
	DWORD			dwFlags;
	LPVOID			lpFormat;
	LPVOID			lpData;
	DWORD			cbData;
	LONG			lTime;
}

struct ICDRAWSUGGEST {
	LPBITMAPINFOHEADER	lpbiIn;
	LPBITMAPINFOHEADER	lpbiSuggest;
	int					dxSrc;
	int					dySrc;
	int					dxDst;
	int					dyDst;
	HIC					hicDecompressor;
}

struct ICPALETTE {
	DWORD			dwFlags;
	int				iStart;
	int				iLen;
	LPPALETTEENTRY	lppe;
}


/**
 * ICM function declarations
 */

extern (Windows) {
	BOOL ICInfo(DWORD fccType, DWORD fccHandler, ICINFO *lpicinfo);
	BOOL ICInstall(DWORD fccType, DWORD fccHandler, LPARAM lParam, LPSTR szDesc, UINT wFlags);
	BOOL ICRemove(DWORD fccType, DWORD fccHandler, UINT wFlags);
	LRESULT ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb);
	HIC ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode);
	HIC ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler);
	LRESULT ICClose(HIC hic);
	LRESULT ICSendMessage(HIC hic, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2);
}

enum {
	ICINSTALL_FUNCTION	= 0x0001,
	ICINSTALL_DRIVER	= 0x0002,
	ICINSTALL_HDRV		= 0x0004,
	ICINSTALL_UNICODE	= 0x8000,
	ICINSTALL_DRIVERW	= 0x8002,
}

// query macros

const ICMF_CONFIGURE_QUERY	= 0x00000001;
const ICMF_ABOUT_QUERY		= 0x00000001;

DWORD ICQueryAbout(HIC hic) {
	return ICSendMessage(hic, ICM_ABOUT, -1, ICMF_ABOUT_QUERY) == ICERR_OK;
}

DWORD ICAbout(HIC hic, HWND hwnd) {
	return ICSendMessage(hic, ICM_ABOUT, cast(UINT)hwnd, 0);
}

DWORD ICQueryConfigure(HIC hic) {
	return (ICSendMessage(hic, ICM_CONFIGURE, -1, ICMF_CONFIGURE_QUERY) == ICERR_OK);
}

DWORD ICConfigure(HIC hic, HWND hwnd) {
	return ICSendMessage(hic, ICM_CONFIGURE, cast(UINT)hwnd, 0);
}

DWORD ICGetState(HIC hic, LPVOID pv, DWORD_PTR cb) {
	return ICSendMessage(hic, ICM_GETSTATE, cast(DWORD)pv, cast(DWORD)cb);
}

DWORD ICSetState(HIC hic, LPVOID pv, DWORD_PTR cb) {
	return ICSendMessage(hic, ICM_SETSTATE, cast(DWORD)pv, cast(DWORD)cb);
}

DWORD ICGetStateSize(HIC hic) {
	return ICGetState(hic, null, 0);
}

DWORD dwICValue;

DWORD ICGetDefaultQuality(HIC hic) {
	ICSendMessage(hic, ICM_GETDEFAULTQUALITY, cast(DWORD_PTR)&dwICValue, DWORD.sizeof);
	return dwICValue;
}

DWORD ICGetDefaultKeyFrameRate(HIC hic) {
	ICSendMessage(hic, ICM_GETDEFAULTKEYFRAMERATE, cast(DWORD_PTR)&dwICValue, DWORD.sizeof);
	return dwICValue;
}

DWORD ICDrawWindow(HIC hic, LPVOID prc) {
	return ICSendMessage(hic, ICM_DRAW_WINDOW, cast(DWORD)prc, RECT.sizeof);
}

extern (Windows) {
	DWORD ICCompress(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiOutput, LPVOID lpData,
		LPBITMAPINFOHEADER lpbiInput, LPVOID lpBits, LPDWORD lpckid, LPDWORD lpdwFlags,
		LONG lFrameNum, DWORD dwFrameSize, DWORD dwQuality, LPBITMAPINFOHEADER lpbiPrev, LPVOID lpPrev);
}

LRESULT ICCompressBegin(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return ICSendMessage(hic, ICM_COMPRESS_BEGIN, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
LRESULT ICCompressQuery(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return ICSendMessage(hic, ICM_COMPRESS_QUERY, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
LRESULT ICCompressGetFormat(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return ICSendMessage(hic, ICM_COMPRESS_GET_FORMAT, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
DWORD ICCompressGetFormatSize(HIC hic, LPVOID lpbi) {
	return cast(DWORD)ICCompressGetFormat(hic, lpbi, null);
}
DWORD ICCompressGetSize(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return cast(DWORD)ICSendMessage(hic, ICM_COMPRESS_GET_SIZE, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
LRESULT ICCompressEnd(HIC hic) {
	return ICSendMessage(hic, ICM_COMPRESS_END, 0, 0);
}

extern (Windows) {
	DWORD ICDecompress(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiFormat, LPVOID lpData, LPBITMAPINFOHEADER lpbi, LPVOID lpBits);
}

LRESULT ICDecompressBegin(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return ICSendMessage(hic, ICM_DECOMPRESS_BEGIN, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
LRESULT ICDecompressQuery(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return ICSendMessage(hic, ICM_DECOMPRESS_QUERY, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
LONG ICDecompressGetFormat(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return cast(LONG)ICSendMessage(hic, ICM_DECOMPRESS_GET_FORMAT, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
LONG ICDecompressGetFormatSize(HIC hic, LPVOID lpbi) {
	return ICDecompressGetFormat(hic, lpbi, null);
}
LRESULT ICDecompressGetPalette(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) {
	return ICSendMessage(hic, ICM_DECOMPRESS_GET_PALETTE, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput);
}
LRESULT ICDecompressSetPalette(HIC hic, LPVOID lpbiPalette) {
	return ICSendMessage(hic, ICM_DECOMPRESS_SET_PALETTE, cast(DWORD_PTR)lpbiPalette, 0);
}
LRESULT ICDecompressEnd(HIC hic) {
	return ICSendMessage(hic, ICM_DECOMPRESS_END, 0, 0);
}

LRESULT ICDecompressEx(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiSrc,
	LPVOID lpSrc, int xSrc, int ySrc, int dxSrc, int dySrc,	LPBITMAPINFOHEADER lpbiDst,
	LPVOID lpDst, int xDst, int yDst, int dxDst, int dyDst) {
	ICDECOMPRESSEX ic;

	ic.dwFlags = dwFlags;
	ic.lpbiSrc = lpbiSrc;
	ic.lpSrc = lpSrc;
	ic.xSrc = xSrc;
	ic.ySrc = ySrc;
	ic.dxSrc = dxSrc;
	ic.dySrc = dySrc;
	ic.lpbiDst = lpbiDst;
	ic.lpDst = lpDst;
	ic.xDst = xDst;
	ic.yDst = yDst;
	ic.dxDst = dxDst;
	ic.dyDst = dyDst;

	return ICSendMessage(hic, ICM_DECOMPRESSEX, cast(DWORD_PTR)&ic, ic.sizeof);
}

LRESULT ICDecompressExBegin(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiSrc,
	LPVOID lpSrc, int xSrc, int ySrc, int dxSrc, int dySrc, LPBITMAPINFOHEADER lpbiDst,
	LPVOID lpDst, int xDst, int yDst, int dxDst, int dyDst) {
	ICDECOMPRESSEX ic;

	ic.dwFlags = dwFlags;
	ic.lpbiSrc = lpbiSrc;
	ic.lpSrc = lpSrc;
	ic.xSrc = xSrc;
	ic.ySrc = ySrc;
	ic.dxSrc = dxSrc;
	ic.dySrc = dySrc;
	ic.lpbiDst = lpbiDst;
	ic.lpDst = lpDst;
	ic.xDst = xDst;
	ic.yDst = yDst;
	ic.dxDst = dxDst;
	ic.dyDst = dyDst;

	return ICSendMessage(hic, ICM_DECOMPRESSEX_BEGIN, cast(DWORD_PTR)&ic, ic.sizeof);
}

LRESULT ICDecompressExQuery(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiSrc,
	LPVOID lpSrc, int xSrc, int ySrc, int dxSrc, int dySrc, LPBITMAPINFOHEADER lpbiDst,
	LPVOID lpDst, int xDst, int yDst, int dxDst, int dyDst) {
	ICDECOMPRESSEX ic;

	ic.dwFlags = dwFlags;
	ic.lpbiSrc = lpbiSrc;
	ic.lpSrc = lpSrc;
	ic.xSrc = xSrc;
	ic.ySrc = ySrc;
	ic.dxSrc = dxSrc;
	ic.dySrc = dySrc;
	ic.lpbiDst = lpbiDst;
	ic.lpDst = lpDst;
	ic.xDst = xDst;
	ic.yDst = yDst;
	ic.dxDst = dxDst;
	ic.dyDst = dyDst;

	return ICSendMessage(hic, ICM_DECOMPRESSEX_QUERY, cast(DWORD_PTR)&ic, ic.sizeof);
}

LRESULT ICDecompressExEnd(HIC hic) {
	return ICSendMessage(hic, ICM_DECOMPRESSEX_END, 0, 0);
}

extern (Windows) {
	DWORD ICDrawBegin(HIC hic, DWORD dwFlags, HPALETTE hpal, HWND hwnd, HDC hdc,
		int xDst, int yDst, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi,
		int xSrc, int ySrc, int dxSrc, int dySrc, DWORD dwRate, DWORD dwScale);
}

extern (Windows) {
	DWORD ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime);
}

LRESULT ICDrawSuggestFormat(HIC hic, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut,
	int dxSrc, int dySrc, int dxDst, int dyDst, HIC hicDecomp) {
	ICDRAWSUGGEST ic;

	ic.lpbiIn = lpbiIn;
	ic.lpbiSuggest = lpbiOut;
	ic.dxSrc = dxSrc;
	ic.dySrc = dySrc;
	ic.dxDst = dxDst;
	ic.dyDst = dyDst;
	ic.hicDecompressor = hicDecomp;

	return ICSendMessage(hic, ICM_DRAW_SUGGESTFORMAT, cast(DWORD_PTR)&ic, ic.sizeof);
}

LRESULT ICDrawQuery(HIC hic, LPVOID lpbiInput) {
	return ICSendMessage(hic, ICM_DRAW_QUERY, cast(DWORD_PTR)lpbiInput, 0L);
}
LRESULT ICDrawChangePalette(HIC hic, LPVOID lpbiInput) {
	return ICSendMessage(hic, ICM_DRAW_CHANGEPALETTE, cast(DWORD_PTR)lpbiInput, 0L);
}
LRESULT ICGetBuffersWanted(HIC hic, LPVOID lpdwBuffers) {
	return ICSendMessage(hic, ICM_GETBUFFERSWANTED, cast(DWORD_PTR)lpdwBuffers, 0);
}
LRESULT ICDrawEnd(HIC hic) {
	return ICSendMessage(hic, ICM_DRAW_END, 0, 0);
}
LRESULT ICDrawStart(HIC hic) {
	return ICSendMessage(hic, ICM_DRAW_START, 0, 0);
}
LRESULT ICDrawStartPlay(HIC hic, DWORD lFrom, DWORD lTo) {
	return ICSendMessage(hic, ICM_DRAW_START_PLAY, cast(DWORD_PTR)lFrom, cast(DWORD_PTR)lTo);
}
LRESULT ICDrawStop(HIC hic) {
	return ICSendMessage(hic, ICM_DRAW_STOP, 0, 0);
}
LRESULT ICDrawStopPlay(HIC hic) {
	return ICSendMessage(hic, ICM_DRAW_STOP_PLAY, 0, 0);
}
LRESULT ICDrawGetTime(HIC hic, LPVOID lplTime) {
	return ICSendMessage(hic, ICM_DRAW_GETTIME, cast(DWORD_PTR)lplTime, 0);
}
LRESULT ICDrawSetTime(HIC hic, DWORD lTime) {
	return ICSendMessage(hic, ICM_DRAW_SETTIME, cast(DWORD_PTR)lTime, 0);
}
LRESULT ICDrawRealize(HIC hic, HDC hdc, BOOL fBackground) {
	return ICSendMessage(hic, ICM_DRAW_REALIZE, cast(DWORD_PTR)hdc, cast(DWORD_PTR)fBackground);
}
LRESULT ICDrawFlush(HIC hic) {
	return ICSendMessage(hic, ICM_DRAW_FLUSH, 0, 0);
}
LRESULT ICDrawRenderBuffer(HIC hic) {
	return ICSendMessage(hic, ICM_DRAW_RENDERBUFFER, 0, 0);
}

LRESULT ICSetStatusProc(HIC hic, DWORD dwFlags, LRESULT lParam, LONG function(LPARAM, UINT, LONG) fpfnStatus) {
	ICSETSTATUSPROC ic;

	ic.dwFlags = dwFlags;
	ic.lParam = lParam;
	ic.Status = fpfnStatus;

	return ICSendMessage(hic, ICM_SET_STATUS_PROC, cast(DWORD_PTR)&ic, ic.sizeof);
}

HIC ICDecompressOpen(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
	return ICLocate(fccType, fccHandler, lpbiIn, lpbiOut, ICMODE_DECOMPRESS);
}

HIC ICDrawOpen(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn) {
	return ICLocate(fccType, fccHandler, lpbiIn, null, ICMODE_DRAW);
}

extern (Windows) {
	HIC ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, WORD wFlags);
	HIC ICGetDisplayFormat(HIC hic, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, int BitDepth, int dx, int dy);
	HANDLE ICImageCompress(HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn, LPVOID lpBits, LPBITMAPINFO lpbiOut, LONG lQuality, LONG* plSize);
	HANDLE ICImageDecompress(HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn, LPVOID lpBits, LPBITMAPINFO lpbiOut);
}

struct COMPVARS {
	LONG		cbSize = this.sizeof;
	DWORD		dwFlags;
	HIC			hic;
	DWORD               fccType;
	DWORD               fccHandler;
	LPBITMAPINFO	lpbiIn;
	LPBITMAPINFO	lpbiOut;
	LPVOID		lpBitsOut;
	LPVOID		lpBitsPrev;
	LONG		lFrame;
	LONG		lKey;
	LONG		lDataRate;
	LONG		lQ;
	LONG		lKeyCount;
	LPVOID		lpState;
	LONG		cbState;
}
alias COMPVARS* PCOMPVARS;

const ICMF_COMPVARS_VALID = 0x00000001;

extern (Windows) {
	BOOL ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn, LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle);
}

enum {
	ICMF_CHOOSE_KEYFRAME		= 0x0001,
	ICMF_CHOOSE_DATARATE		= 0x0002,
	ICMF_CHOOSE_PREVIEW			= 0x0004,
	ICMF_CHOOSE_ALLCOMPRESSORS	= 0x0008,
}

extern (Windows) {
	BOOL ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn);
	void ICSeqCompressFrameEnd(PCOMPVARS pc);
	LPVOID ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL* pfKey, LONG* plSize);
	void ICCompressorFree(PCOMPVARS pc);
}

alias HANDLE HDRAWDIB;

enum {
	DDF_0001			= 0x0001,
	DDF_UPDATE			= 0x0002,
	DDF_SAME_HDC		= 0x0004,
	DDF_SAME_DRAW		= 0x0008,
	DDF_DONTDRAW		= 0x0010,
	DDF_ANIMATE			= 0x0020,
	DDF_BUFFER			= 0x0040,
	DDF_JUSTDRAWIT		= 0x0080,
	DDF_FULLSCREEN		= 0x0100,
	DDF_BACKGROUNDPAL	= 0x0200,
	DDF_NOTKEYFRAME		= 0x0400,
	DDF_HURRYUP			= 0x0800,
	DDF_HALFTONE		= 0x1000,
	DDF_2000			= 0x2000,
	DDF_PREROLL			= DDF_DONTDRAW,
	DDF_SAME_DIB		= DDF_SAME_DRAW,
	DDF_SAME_SIZE		= DDF_SAME_DRAW,
}

extern (Windows) {
	BOOL DrawDibInit();
	HDRAWDIB DrawDibOpen();
	BOOL DrawDibClose(HDRAWDIB hdd);
	LPVOID DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags);
	UINT DrawDibError(HDRAWDIB hdd);
	HPALETTE DrawDibGetPalette(HDRAWDIB hdd);
	BOOL DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal);
	BOOL DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe);
	UINT DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground);
	BOOL DrawDibStart(HDRAWDIB hdd, DWORD rate);
	BOOL DrawDibStop(HDRAWDIB hdd);
	BOOL DrawDibBegin(HDRAWDIB hdd, HDC hdc, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi, int dxSrc, int dySrc, UINT wFlags);
	BOOL DrawDibDraw(HDRAWDIB hdd, HDC hdc, int xDst, int yDst, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi,
		LPVOID lpBits, int xSrc, int ySrc, int dxSrc, int dySrc, UINT wFlags);
}

BOOL DrawDibUpdate(HDRAWDIB hdd, HDC hdc, int x, int y) {
	return DrawDibDraw(hdd, hdc, x, y, 0, 0, null, null, 0, 0, 0, 0, DDF_UPDATE);
}

extern (Windows) {
	BOOL DrawDibEnd(HDRAWDIB hdd);
}

struct DRAWDIBTIME {
    LONG    timeCount;
    LONG    timeDraw;
    LONG    timeDecompress;
    LONG    timeDither;
    LONG    timeStretch;
    LONG    timeBlt;
    LONG    timeSetDIBits;
}
alias DRAWDIBTIME* LPDRAWDIBTIME;

extern (Windows) {
	BOOL DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime);
}

enum {
	PD_CAN_DRAW_DIB			= 0x0001,
	PD_CAN_STRETCHDIB		= 0x0002,
	PD_STRETCHDIB_1_1_OK	= 0x0004,
	PD_STRETCHDIB_1_2_OK	= 0x0008,
	PD_STRETCHDIB_1_N_OK	= 0x0010,
}

extern (Windows) {
	LRESULT DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi);
	void StretchDIB(LPBITMAPINFOHEADER biDst, LPVOID lpDst, int	DstX, int DstY,
		int DstXE, int DstYE, LPBITMAPINFOHEADER biSrc, LPVOID lpSrc,
		int SrcX, int SrcY, int SrcXE, int SrcYE);
} 	

alias DWORD FOURCC;

alias WORD TWOCC;

const formtypeAVI			= mmioFOURCC!('A', 'V', 'I', ' ');
const listtypeAVIHEADER		= mmioFOURCC!('h', 'd', 'r', 'l');
const ckidAVIMAINHDR		= mmioFOURCC!('a', 'v', 'i', 'h');
const listtypeSTREAMHEADER	= mmioFOURCC!('s', 't', 'r', 'l');
const ckidSTREAMHEADER		= mmioFOURCC!('s', 't', 'r', 'h');
const ckidSTREAMFORMAT		= mmioFOURCC!('s', 't', 'r', 'f');
const ckidSTREAMHANDLERDATA	= mmioFOURCC!('s', 't', 'r', 'd');
const ckidSTREAMNAME		= mmioFOURCC!('s', 't', 'r', 'n');
const listtypeAVIMOVIE		= mmioFOURCC!('m', 'o', 'v', 'i');
const listtypeAVIRECORD		= mmioFOURCC!('r', 'e', 'c', ' ');
const ckidAVINEWINDEX		= mmioFOURCC!('i', 'd', 'x', '1');
const streamtypeVIDEO		= mmioFOURCC!('v', 'i', 'd', 's');
const streamtypeAUDIO		= mmioFOURCC!('a', 'u', 'd', 's');
const streamtypeMIDI		= mmioFOURCC!('m', 'i', 'd', 's');
const streamtypeTEXT		= mmioFOURCC!('t', 'x', 't', 's');

const cktypeDIBbits			= aviTWOCC!('d', 'b');
const cktypeDIBcompressed	= aviTWOCC!('d', 'c');
const cktypePALchange		= aviTWOCC!('p', 'c');
const cktypeWAVEbytes		= aviTWOCC!('w', 'b');

const ckidAVIPADDING		= mmioFOURCC!('J', 'U', 'N', 'K');

DWORD FromHex(char n) {
	return (n >= 'A') ? n + 10 - 'A' : n - '0';
}

WORD StreamFromFOURCC(DWORD fcc) {
	return cast(WORD)((FromHex(LOBYTE(LOWORD(fcc))) << 4) + (FromHex(HIBYTE(LOWORD(fcc)))));
}

WORD TWOCCFromFOURCC(DWORD fcc) {
	return HIWORD(fcc);
}

BYTE ToHex(DWORD n) {
	return cast(BYTE)((n > 9) ? n - 10 + 'A' : n + '0');
}

DWORD MAKEAVICKID(WORD tcc, WORD stream) {
	return MAKELONG(cast(WORD)((ToHex(stream & 0x0f) << 8) | (ToHex((stream & 0xf0) >> 4))), tcc);
}

enum {
	AVIF_HASINDEX		= 0x00000010,
	AVIF_MUSTUSEINDEX	= 0x00000020,
	AVIF_ISINTERLEAVED	= 0x00000100,
	AVIF_WASCAPTUREFILE	= 0x00010000,
	AVIF_COPYRIGHTED	= 0x00020000,
}

const AVI_HEADERSIZE = 2048;

struct MainAVIHeader {
	DWORD dwMicroSecPerFrame;
	DWORD dwMaxBytesPerSec;
	DWORD dwPaddingGranularity;
	DWORD dwFlags;
	DWORD dwTotalFrames;
	DWORD dwInitialFrames;
	DWORD dwStreams;
	DWORD dwSuggestedBufferSize;
	DWORD dwWidth;
	DWORD dwHeight;
	DWORD dwReserved[4];
}

const AVISF_DISABLED = 0x00000001;

const AVISF_VIDEO_PALCHANGES = 0x00010000;

struct AVIStreamHeader {
	FOURCC		fccType;
	FOURCC		fccHandler;
	DWORD		dwFlags;
	WORD		wPriority;
	WORD		wLanguage;
	DWORD		dwInitialFrames;
	DWORD		dwScale;	
	DWORD		dwRate;
	DWORD		dwStart;
	DWORD		dwLength;
	DWORD		dwSuggestedBufferSize;
	DWORD		dwQuality;
	DWORD		dwSampleSize;
	RECT		rcFrame;
}

enum {
	AVIIF_FIRSTPART	= 0x00000020L,
	AVIIF_LASTPART	= 0x00000040L,
	AVIIF_MIDPART	= (AVIIF_LASTPART|AVIIF_FIRSTPART),
	AVIIF_NOTIME	= 0x00000100L,
	AVIIF_COMPUSE	= 0x0FFF0000L,
}

struct AVIINDEXENTRY {
	DWORD		ckid;
	DWORD		dwFlags;
	DWORD		dwChunkOffset;
	DWORD		dwChunkLength;
}

struct AVIPALCHANGE {
	BYTE		bFirstEntry;
	BYTE		bNumEntries;
	WORD		wFlags;
	PALETTEENTRY	peNew[];
}

const AVIGETFRAMEF_BESTDISPLAYFMT = 1;

struct AVISTREAMINFOW {
	DWORD	fccType;
	DWORD	fccHandler;
	DWORD	dwFlags;
	DWORD	dwCaps;
	WORD	wPriority;
	WORD	wLanguage;
	DWORD	dwScale;
	DWORD	dwRate;
	DWORD	dwStart;
	DWORD	dwLength;
	DWORD	dwInitialFrames;
	DWORD	dwSuggestedBufferSize;
	DWORD	dwQuality;
	DWORD	dwSampleSize;
	RECT	rcFrame;
	DWORD	dwEditCount;
	DWORD	dwFormatChangeCount;
	WCHAR	szName[64];
}
alias AVISTREAMINFOW* LPAVISTREAMINFOW;

struct AVISTREAMINFOA {
	DWORD	fccType;
	DWORD	fccHandler;
	DWORD	dwFlags;
	DWORD	dwCaps;
	WORD	wPriority;
	WORD	wLanguage;
	DWORD	dwScale;
	DWORD	dwRate;
	DWORD	dwStart;
	DWORD	dwLength;
	DWORD	dwInitialFrames;
	DWORD	dwSuggestedBufferSize;
	DWORD	dwQuality;
	DWORD	dwSampleSize;
	RECT	rcFrame;
	DWORD	dwEditCount;
	DWORD	dwFormatChangeCount;
	char	szName[64];
}
alias AVISTREAMINFOA* LPAVISTREAMINFOA;

version(Unicode) {
	alias AVISTREAMINFOW	AVISTREAMINFO;
	alias LPAVISTREAMINFOW	LPAVISTREAMINFO;
} else { // Unicode
	alias AVISTREAMINFOA	AVISTREAMINFO;
	alias LPAVISTREAMINFOA	LPAVISTREAMINFO;
}

const AVISTREAMINFO_DISABLED		= 0x00000001;
const AVISTREAMINFO_FORMATCHANGES	= 0x00010000;

struct AVIFILEINFOW {
	DWORD	dwMaxBytesPerSec;
	DWORD	dwFlags;
	DWORD	dwCaps;
	DWORD	dwStreams;
	DWORD	dwSuggestedBufferSize;
	DWORD	dwWidth;
	DWORD	dwHeight;
	DWORD	dwScale;	
	DWORD	dwRate;
	DWORD	dwLength;
	DWORD	dwEditCount;
	WCHAR	szFileType[64];
}
alias AVIFILEINFOW* LPAVIFILEINFOW;

struct AVIFILEINFOA {
	DWORD	dwMaxBytesPerSec;
	DWORD	dwFlags;
	DWORD	dwCaps;
	DWORD	dwStreams;
	DWORD	dwSuggestedBufferSize;
	DWORD	dwWidth;
	DWORD	dwHeight;
	DWORD	dwScale;	
	DWORD	dwRate;
	DWORD	dwLength;
	DWORD	dwEditCount;
	char	szFileType[64];
}
alias AVIFILEINFOA* LPAVIFILEINFOA;

version(Unicode) {
	alias AVIFILEINFOW	AVIFILEINFO;
	alias LPAVIFILEINFOW	LPAVIFILEINFO;
} else { // Unicode
	alias AVIFILEINFOA	AVIFILEINFO;
	alias LPAVIFILEINFOA	LPAVIFILEINFO;
}

enum {
	AVIFILEINFO_HASINDEX		= 0x00000010,
	AVIFILEINFO_MUSTUSEINDEX	= 0x00000020,
	AVIFILEINFO_ISINTERLEAVED	= 0x00000100,
	AVIFILEINFO_WASCAPTUREFILE	= 0x00010000,
	AVIFILEINFO_COPYRIGHTED		= 0x00020000,
}

enum {
	AVIFILECAPS_CANREAD			= 0x00000001,
	AVIFILECAPS_CANWRITE		= 0x00000002,
	AVIFILECAPS_ALLKEYFRAMES	= 0x00000010,
	AVIFILECAPS_NOCOMPRESSION	= 0x00000020,
}

extern (Windows) {
	alias BOOL function(int) AVISAVECALLBACK;
}

struct AVICOMPRESSOPTIONS {
	DWORD	fccType;
	DWORD	fccHandler;
	DWORD	dwKeyFrameEvery;
	DWORD	dwQuality;
	DWORD	dwBytesPerSecond;
	DWORD	dwFlags;
	LPVOID	lpFormat;
	DWORD	cbFormat;
	LPVOID	lpParms;
	DWORD	cbParms;
	DWORD	dwInterleaveEvery;
}
alias AVICOMPRESSOPTIONS* LPAVICOMPRESSOPTIONS;

enum {
	AVICOMPRESSF_INTERLEAVE	= 0x00000001,
	AVICOMPRESSF_DATARATE	= 0x00000002,
	AVICOMPRESSF_KEYFRAMES	= 0x00000004,
	AVICOMPRESSF_VALID		= 0x00000008,
}

/+ TODO:
DECLARE_INTERFACE_(IAVIStream, IUnknown)
{
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
    STDMETHOD_(ULONG,Release) (THIS) PURE;

    STDMETHOD(Create)      (THIS_ LPARAM lParam1, LPARAM lParam2) PURE ;
    STDMETHOD(Info)        (THIS_ AVISTREAMINFOW FAR * psi, LONG lSize) PURE ;
    STDMETHOD_(LONG, FindSample)(THIS_ LONG lPos, LONG lFlags) PURE ;
    STDMETHOD(ReadFormat)  (THIS_ LONG lPos,
			    LPVOID lpFormat, LONG FAR *lpcbFormat) PURE ;
    STDMETHOD(SetFormat)   (THIS_ LONG lPos,
			    LPVOID lpFormat, LONG cbFormat) PURE ;
    STDMETHOD(Read)        (THIS_ LONG lStart, LONG lSamples,
			    LPVOID lpBuffer, LONG cbBuffer,
			    LONG FAR * plBytes, LONG FAR * plSamples) PURE ;
    STDMETHOD(Write)       (THIS_ LONG lStart, LONG lSamples,
			    LPVOID lpBuffer, LONG cbBuffer,
			    DWORD dwFlags,
			    LONG FAR *plSampWritten,
			    LONG FAR *plBytesWritten) PURE ;
    STDMETHOD(Delete)      (THIS_ LONG lStart, LONG lSamples) PURE;
    STDMETHOD(ReadData)    (THIS_ DWORD fcc, LPVOID lp, LONG FAR *lpcb) PURE ;
    STDMETHOD(WriteData)   (THIS_ DWORD fcc, LPVOID lp, LONG cb) PURE ;
#ifdef _WIN32
    STDMETHOD(SetInfo) (THIS_ AVISTREAMINFOW FAR * lpInfo,
			    LONG cbInfo) PURE;
#else
    STDMETHOD(Reserved1)            (THIS) PURE;
    STDMETHOD(Reserved2)            (THIS) PURE;
    STDMETHOD(Reserved3)            (THIS) PURE;
    STDMETHOD(Reserved4)            (THIS) PURE;
    STDMETHOD(Reserved5)            (THIS) PURE;
#endif
};

typedef       IAVIStream FAR* PAVISTREAM;

#undef  INTERFACE
#define INTERFACE   IAVIStreaming

DECLARE_INTERFACE_(IAVIStreaming, IUnknown)
{
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
    STDMETHOD_(ULONG,Release) (THIS) PURE;

    STDMETHOD(Begin) (THIS_
		      LONG  lStart,
		      LONG  lEnd,
		      LONG  lRate) PURE;
    STDMETHOD(End)   (THIS) PURE;
};

typedef       IAVIStreaming FAR* PAVISTREAMING;


#undef  INTERFACE
#define INTERFACE   IAVIEditStream

DECLARE_INTERFACE_(IAVIEditStream, IUnknown)
{
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
    STDMETHOD_(ULONG,Release) (THIS) PURE;

    STDMETHOD(Cut) (THIS_ LONG FAR *plStart,
			  LONG FAR *plLength,
			  PAVISTREAM FAR * ppResult) PURE;
    STDMETHOD(Copy) (THIS_ LONG FAR *plStart,
			   LONG FAR *plLength,
			   PAVISTREAM FAR * ppResult) PURE;
    STDMETHOD(Paste) (THIS_ LONG FAR *plPos,
			    LONG FAR *plLength,
			    PAVISTREAM pstream,
			    LONG lStart,
			    LONG lEnd) PURE;
    STDMETHOD(Clone) (THIS_ PAVISTREAM FAR *ppResult) PURE;
    STDMETHOD(SetInfo) (THIS_ AVISTREAMINFOW FAR * lpInfo,
			    LONG cbInfo) PURE;
};

typedef       IAVIEditStream FAR* PAVIEDITSTREAM;

#undef  INTERFACE
#define INTERFACE   IAVIPersistFile

DECLARE_INTERFACE_(IAVIPersistFile, IPersistFile)
{
    STDMETHOD(Reserved1)(THIS) PURE;
};

typedef IAVIPersistFile FAR* PAVIPERSISTFILE;

#undef  INTERFACE
#define INTERFACE   IAVIFile
#define PAVIFILE IAVIFile FAR*

DECLARE_INTERFACE_(IAVIFile, IUnknown)
{
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
    STDMETHOD_(ULONG,Release) (THIS) PURE;

    STDMETHOD(Info)                 (THIS_
                                     AVIFILEINFOW FAR * pfi,
                                     LONG lSize) PURE;
    STDMETHOD(GetStream)            (THIS_
                                     PAVISTREAM FAR * ppStream,
				     DWORD fccType,
                                     LONG lParam) PURE;
    STDMETHOD(CreateStream)         (THIS_
                                     PAVISTREAM FAR * ppStream,
                                     AVISTREAMINFOW FAR * psi) PURE;
    STDMETHOD(WriteData)            (THIS_
                                     DWORD ckid,
                                     LPVOID lpData,
                                     LONG cbData) PURE;
    STDMETHOD(ReadData)             (THIS_
                                     DWORD ckid,
                                     LPVOID lpData,
                                     LONG FAR *lpcbData) PURE;
    STDMETHOD(EndRecord)            (THIS) PURE;
    STDMETHOD(DeleteStream)         (THIS_
				     DWORD fccType,
                                     LONG lParam) PURE;
};

#undef PAVIFILE
typedef       IAVIFile FAR* PAVIFILE;

#undef  INTERFACE
#define INTERFACE   IGetFrame
#define PGETFRAME   IGetFrame FAR*

DECLARE_INTERFACE_(IGetFrame, IUnknown)
{
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
    STDMETHOD_(ULONG,Release) (THIS) PURE;

    STDMETHOD_(LPVOID,GetFrame) (THIS_ LONG lPos) PURE;

    STDMETHOD(Begin) (THIS_ LONG lStart, LONG lEnd, LONG lRate) PURE;
    STDMETHOD(End) (THIS) PURE;

    STDMETHOD(SetFormat) (THIS_ LPBITMAPINFOHEADER lpbi, LPVOID lpBits, int x, int y, int dx, int dy) PURE;
};

#undef PGETFRAME
typedef IGetFrame FAR* PGETFRAME;

#define DEFINE_AVIGUID(name, l, w1, w2)    DEFINE_GUID(name, l, w1, w2, 0xC0,0,0,0,0,0,0,0x46)

DEFINE_AVIGUID(IID_IAVIFile,            0x00020020, 0, 0);
DEFINE_AVIGUID(IID_IAVIStream,          0x00020021, 0, 0);
DEFINE_AVIGUID(IID_IAVIStreaming,       0x00020022, 0, 0);
DEFINE_AVIGUID(IID_IGetFrame,           0x00020023, 0, 0);
DEFINE_AVIGUID(IID_IAVIEditStream,      0x00020024, 0, 0);
DEFINE_AVIGUID(IID_IAVIPersistFile,     0x00020025, 0, 0);
#ifndef UNICODE
DEFINE_AVIGUID(CLSID_AVISimpleUnMarshal,        0x00020009, 0, 0);
#endif

DEFINE_AVIGUID(CLSID_AVIFile,           0x00020000, 0, 0);

#define	AVIFILEHANDLER_CANREAD		0x0001
#define	AVIFILEHANDLER_CANWRITE		0x0002
#define	AVIFILEHANDLER_CANACCEPTNONRGB	0x0004

STDAPI_(void) AVIFileInit(void);
STDAPI_(void) AVIFileExit(void);

STDAPI_(ULONG) AVIFileAddRef       (PAVIFILE pfile);
STDAPI_(ULONG) AVIFileRelease      (PAVIFILE pfile);

#ifdef _WIN32
STDAPI AVIFileOpenA       (PAVIFILE FAR * ppfile, LPCSTR szFile,
			  UINT uMode, LPCLSID lpHandler);
STDAPI AVIFileOpenW       (PAVIFILE FAR * ppfile, LPCWSTR szFile,
			  UINT uMode, LPCLSID lpHandler);
#ifdef UNICODE
#define AVIFileOpen	  AVIFileOpenW	
#else
#define AVIFileOpen	  AVIFileOpenA	
#endif
#else
STDAPI AVIFileOpen       (PAVIFILE FAR * ppfile, LPCSTR szFile,
			  UINT uMode, LPCLSID lpHandler);
#define AVIFileOpenW	AVIFileOpen
#endif

#ifdef _WIN32
STDAPI AVIFileInfoW (PAVIFILE pfile, LPAVIFILEINFOW pfi, LONG lSize);
STDAPI AVIFileInfoA (PAVIFILE pfile, LPAVIFILEINFOA pfi, LONG lSize);
#ifdef UNICODE
#define AVIFileInfo	AVIFileInfoW
#else
#define AVIFileInfo	AVIFileInfoA
#endif
#else
STDAPI AVIFileInfo (PAVIFILE pfile, LPAVIFILEINFO pfi, LONG lSize);
#define AVIFileInfoW AVIFileInfo
#endif


STDAPI AVIFileGetStream     (PAVIFILE pfile, PAVISTREAM FAR * ppavi, DWORD fccType, LONG lParam);


#ifdef _WIN32
STDAPI AVIFileCreateStreamW (PAVIFILE pfile, PAVISTREAM FAR *ppavi, AVISTREAMINFOW FAR * psi);
STDAPI AVIFileCreateStreamA (PAVIFILE pfile, PAVISTREAM FAR *ppavi, AVISTREAMINFOA FAR * psi);
#ifdef UNICODE
#define AVIFileCreateStream	AVIFileCreateStreamW
#else
#define AVIFileCreateStream	AVIFileCreateStreamA
#endif
#else
STDAPI AVIFileCreateStream(PAVIFILE pfile, PAVISTREAM FAR *ppavi, AVISTREAMINFO FAR * psi);
#define AVIFileCreateStreamW AVIFileCreateStream
#endif

STDAPI AVIFileWriteData	(PAVIFILE pfile,
					 DWORD ckid,
					 LPVOID lpData,
					 LONG cbData);
STDAPI AVIFileReadData	(PAVIFILE pfile,
					 DWORD ckid,
					 LPVOID lpData,
					 LONG FAR *lpcbData);
STDAPI AVIFileEndRecord	(PAVIFILE pfile);

STDAPI_(ULONG) AVIStreamAddRef       (PAVISTREAM pavi);
STDAPI_(ULONG) AVIStreamRelease      (PAVISTREAM pavi);

STDAPI AVIStreamInfoW (PAVISTREAM pavi, LPAVISTREAMINFOW psi, LONG lSize);
STDAPI AVIStreamInfoA (PAVISTREAM pavi, LPAVISTREAMINFOA psi, LONG lSize);
#ifdef UNICODE
#define AVIStreamInfo	AVIStreamInfoW
#else
#define AVIStreamInfo	AVIStreamInfoA
#endif

STDAPI_(LONG) AVIStreamFindSample(PAVISTREAM pavi, LONG lPos, LONG lFlags);
STDAPI AVIStreamReadFormat   (PAVISTREAM pavi, LONG lPos,LPVOID lpFormat,LONG FAR *lpcbFormat);
STDAPI AVIStreamSetFormat    (PAVISTREAM pavi, LONG lPos,LPVOID lpFormat,LONG cbFormat);
STDAPI AVIStreamReadData     (PAVISTREAM pavi, DWORD fcc, LPVOID lp, LONG FAR *lpcb);
STDAPI AVIStreamWriteData    (PAVISTREAM pavi, DWORD fcc, LPVOID lp, LONG cb);

STDAPI AVIStreamRead         (PAVISTREAM pavi,
			      LONG lStart,
			      LONG lSamples,
			      LPVOID lpBuffer,
			      LONG cbBuffer,
			      LONG FAR * plBytes,
			      LONG FAR * plSamples);
#define AVISTREAMREAD_CONVENIENT	(-1L)

STDAPI AVIStreamWrite        (PAVISTREAM pavi,
			      LONG lStart, LONG lSamples,
			      LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags,
			      LONG FAR *plSampWritten,
			      LONG FAR *plBytesWritten);

STDAPI_(LONG) AVIStreamStart        (PAVISTREAM pavi);
STDAPI_(LONG) AVIStreamLength       (PAVISTREAM pavi);
STDAPI_(LONG) AVIStreamTimeToSample (PAVISTREAM pavi, LONG lTime);
STDAPI_(LONG) AVIStreamSampleToTime (PAVISTREAM pavi, LONG lSample);


STDAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate);
STDAPI AVIStreamEndStreaming(PAVISTREAM pavi);

STDAPI_(PGETFRAME) AVIStreamGetFrameOpen(PAVISTREAM pavi,
					 LPBITMAPINFOHEADER lpbiWanted);
STDAPI_(LPVOID) AVIStreamGetFrame(PGETFRAME pg, LONG lPos);
STDAPI AVIStreamGetFrameClose(PGETFRAME pg);

STDAPI AVIStreamOpenFromFileA(PAVISTREAM FAR *ppavi, LPCSTR szFile,
			     DWORD fccType, LONG lParam,
			     UINT mode, CLSID FAR *pclsidHandler);
STDAPI AVIStreamOpenFromFileW(PAVISTREAM FAR *ppavi, LPCWSTR szFile,
			     DWORD fccType, LONG lParam,
			     UINT mode, CLSID FAR *pclsidHandler);
#ifdef UNICODE
#define AVIStreamOpenFromFile	AVIStreamOpenFromFileW
#else
#define AVIStreamOpenFromFile	AVIStreamOpenFromFileA
#endif

STDAPI AVIStreamCreate(PAVISTREAM FAR *ppavi, LONG lParam1, LONG lParam2,
		       CLSID FAR *pclsidHandler);



#define FIND_DIR        0x0000000FL
#define FIND_NEXT       0x00000001L
#define FIND_PREV       0x00000004L
#define FIND_FROM_START 0x00000008L

#define FIND_TYPE       0x000000F0L
#define FIND_KEY        0x00000010L
#define FIND_ANY        0x00000020L
#define FIND_FORMAT     0x00000040L

#define FIND_RET        0x0000F000L
#define FIND_POS        0x00000000L
#define FIND_LENGTH     0x00001000L
#define FIND_OFFSET     0x00002000L
#define FIND_SIZE       0x00003000L
#define FIND_INDEX      0x00004000L

#define AVIStreamFindKeyFrame AVIStreamFindSample
#define FindKeyFrame	FindSample

#define AVIStreamClose AVIStreamRelease
#define AVIFileClose   AVIFileRelease
#define AVIStreamInit  AVIFileInit
#define AVIStreamExit  AVIFileExit

#define SEARCH_NEAREST  FIND_PREV
#define SEARCH_BACKWARD FIND_PREV
#define SEARCH_FORWARD  FIND_NEXT
#define SEARCH_KEY      FIND_KEY
#define SEARCH_ANY      FIND_ANY

#define     AVIStreamSampleToSample(pavi1, pavi2, l)            AVIStreamTimeToSample(pavi1,AVIStreamSampleToTime(pavi2, l))

#define     AVIStreamNextSample(pavi, l)            AVIStreamFindSample(pavi,l+1,FIND_NEXT|FIND_ANY)

#define     AVIStreamPrevSample(pavi, l)            AVIStreamFindSample(pavi,l-1,FIND_PREV|FIND_ANY)

#define     AVIStreamNearestSample(pavi, l)            AVIStreamFindSample(pavi,l,FIND_PREV|FIND_ANY)

#define     AVIStreamNextKeyFrame(pavi,l)            AVIStreamFindSample(pavi,l+1,FIND_NEXT|FIND_KEY)

#define     AVIStreamPrevKeyFrame(pavi, l)            AVIStreamFindSample(pavi,l-1,FIND_PREV|FIND_KEY)

#define     AVIStreamNearestKeyFrame(pavi, l)            AVIStreamFindSample(pavi,l,FIND_PREV|FIND_KEY)

#define     AVIStreamIsKeyFrame(pavi, l)            (AVIStreamNearestKeyFrame(pavi,l) == l)

#define     AVIStreamPrevSampleTime(pavi, t)            AVIStreamSampleToTime(pavi, AVIStreamPrevSample(pavi,AVIStreamTimeToSample(pavi,t)))

#define     AVIStreamNextSampleTime(pavi, t)            AVIStreamSampleToTime(pavi, AVIStreamNextSample(pavi,AVIStreamTimeToSample(pavi,t)))

#define     AVIStreamNearestSampleTime(pavi, t)            AVIStreamSampleToTime(pavi, AVIStreamNearestSample(pavi,AVIStreamTimeToSample(pavi,t)))

#define     AVIStreamNextKeyFrameTime(pavi, t)            AVIStreamSampleToTime(pavi, AVIStreamNextKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)))

#define     AVIStreamPrevKeyFrameTime(pavi, t)            AVIStreamSampleToTime(pavi, AVIStreamPrevKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)))

#define     AVIStreamNearestKeyFrameTime(pavi, t)            AVIStreamSampleToTime(pavi, AVIStreamNearestKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)))

#define     AVIStreamStartTime(pavi)            AVIStreamSampleToTime(pavi, AVIStreamStart(pavi))

#define     AVIStreamLengthTime(pavi)            AVIStreamSampleToTime(pavi, AVIStreamLength(pavi))

#define     AVIStreamEnd(pavi)            (AVIStreamStart(pavi) + AVIStreamLength(pavi))

#define     AVIStreamEndTime(pavi)            AVIStreamSampleToTime(pavi, AVIStreamEnd(pavi))

#define     AVIStreamSampleSize(pavi, lPos, plSize)	    AVIStreamRead(pavi,lPos,1,NULL,0,plSize,NULL)

#define     AVIStreamFormatSize(pavi, lPos, plSize)            AVIStreamReadFormat(pavi,lPos,NULL,plSize)

#define     AVIStreamDataSize(pavi, fcc, plSize)            AVIStreamReadData(pavi,fcc,NULL,plSize)

#ifndef comptypeDIB
#define comptypeDIB         mmioFOURCC('D', 'I', 'B', ' ')
#endif

STDAPI AVIMakeCompressedStream(
		PAVISTREAM FAR *	    ppsCompressed,
		PAVISTREAM		    ppsSource,
		AVICOMPRESSOPTIONS FAR *    lpOptions,
		CLSID FAR *pclsidHandler);

EXTERN_C HRESULT CDECL AVISaveA (LPCSTR               szFile,
		CLSID FAR *pclsidHandler,
		AVISAVECALLBACK     lpfnCallback,
		int                 nStreams,
		PAVISTREAM	    pfile,
		LPAVICOMPRESSOPTIONS lpOptions,
		...);

STDAPI AVISaveVA(LPCSTR               szFile,
		CLSID FAR *pclsidHandler,
		AVISAVECALLBACK     lpfnCallback,
		int                 nStreams,
		PAVISTREAM FAR *    ppavi,
		LPAVICOMPRESSOPTIONS FAR *plpOptions);
EXTERN_C HRESULT CDECL AVISaveW (LPCWSTR               szFile,
		CLSID FAR *pclsidHandler,
		AVISAVECALLBACK     lpfnCallback,
		int                 nStreams,
		PAVISTREAM	    pfile,
		LPAVICOMPRESSOPTIONS lpOptions,
		...);

STDAPI AVISaveVW(LPCWSTR               szFile,
		CLSID FAR *pclsidHandler,
		AVISAVECALLBACK     lpfnCallback,
		int                 nStreams,
		PAVISTREAM FAR *    ppavi,
		LPAVICOMPRESSOPTIONS FAR *plpOptions);
#ifdef UNICODE
#define AVISave		AVISaveW
#define AVISaveV	AVISaveVW
#else
#define AVISave		AVISaveA
#define AVISaveV	AVISaveVA
#endif



STDAPI_(INT_PTR) AVISaveOptions(HWND hwnd,
			     UINT	uiFlags,
			     int	nStreams,
			     PAVISTREAM FAR *ppavi,
			     LPAVICOMPRESSOPTIONS FAR *plpOptions);

STDAPI AVISaveOptionsFree(int nStreams,
			     LPAVICOMPRESSOPTIONS FAR *plpOptions);

STDAPI AVIBuildFilterW(LPWSTR lpszFilter, LONG cbFilter, BOOL fSaving);
STDAPI AVIBuildFilterA(LPSTR lpszFilter, LONG cbFilter, BOOL fSaving);
#ifdef UNICODE
#define AVIBuildFilter	AVIBuildFilterW
#else
#define AVIBuildFilter	AVIBuildFilterA
#endif
STDAPI AVIMakeFileFromStreams(PAVIFILE FAR *	ppfile,
			       int		nStreams,
			       PAVISTREAM FAR *	papStreams);

STDAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal, PAVISTREAM FAR *ppstream);

STDAPI AVIPutFileOnClipboard(PAVIFILE pf);

STDAPI AVIGetFromClipboard(PAVIFILE FAR * lppf);

STDAPI AVIClearClipboard(void);

STDAPI CreateEditableStream(
		PAVISTREAM FAR *	    ppsEditable,
		PAVISTREAM		    psSource);

STDAPI EditStreamCut(PAVISTREAM pavi, LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult);

STDAPI EditStreamCopy(PAVISTREAM pavi, LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult);

STDAPI EditStreamPaste(PAVISTREAM pavi, LONG FAR *plPos, LONG FAR *plLength, PAVISTREAM pstream, LONG lStart, LONG lEnd);

STDAPI EditStreamClone(PAVISTREAM pavi, PAVISTREAM FAR *ppResult);


STDAPI EditStreamSetNameA(PAVISTREAM pavi, LPCSTR lpszName);
STDAPI EditStreamSetNameW(PAVISTREAM pavi, LPCWSTR lpszName);
STDAPI EditStreamSetInfoW(PAVISTREAM pavi, LPAVISTREAMINFOW lpInfo, LONG cbInfo);
STDAPI EditStreamSetInfoA(PAVISTREAM pavi, LPAVISTREAMINFOA lpInfo, LONG cbInfo);
#ifdef UNICODE
#define EditStreamSetInfo	EditStreamSetInfoW
#define EditStreamSetName	EditStreamSetNameW
#else
#define EditStreamSetInfo	EditStreamSetInfoA
#define EditStreamSetName	EditStreamSetNameA
#endif
+/
const AVIERR_OK = 0L;

SCODE MAKE_AVIERR(DWORD error) {
	return MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x4000 + error);
}

const AVIERR_UNSUPPORTED	= MAKE_AVIERR(101);
const AVIERR_BADFORMAT		= MAKE_AVIERR(102);
const AVIERR_MEMORY			= MAKE_AVIERR(103);
const AVIERR_INTERNAL		= MAKE_AVIERR(104);
const AVIERR_BADFLAGS		= MAKE_AVIERR(105);
const AVIERR_BADPARAM		= MAKE_AVIERR(106);
const AVIERR_BADSIZE		= MAKE_AVIERR(107);
const AVIERR_BADHANDLE		= MAKE_AVIERR(108);
const AVIERR_FILEREAD		= MAKE_AVIERR(109);
const AVIERR_FILEWRITE		= MAKE_AVIERR(110);
const AVIERR_FILEOPEN		= MAKE_AVIERR(111);
const AVIERR_COMPRESSOR		= MAKE_AVIERR(112);
const AVIERR_NOCOMPRESSOR	= MAKE_AVIERR(113);
const AVIERR_READONLY		= MAKE_AVIERR(114);
const AVIERR_NODATA			= MAKE_AVIERR(115);
const AVIERR_BUFFERTOOSMALL	= MAKE_AVIERR(116);
const AVIERR_CANTCOMPRESS	= MAKE_AVIERR(117);
const AVIERR_USERABORT		= MAKE_AVIERR(198);
const AVIERR_ERROR			= MAKE_AVIERR(199);

const TCHAR[] MCIWND_WINDOW_CLASS = "MCIWndClass";

extern (Windows) {
	HWND MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPCSTR szFile);
	HWND MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPCWSTR szFile);
}

version(Unicode) {
	alias MCIWndCreateW	MCIWndCreate;
} else { // Unicode
	alias MCIWndCreateA	MCIWndCreate;
}

extern(Windows) {
	BOOL MCIWndRegisterClass();
}

enum {
	MCIWNDOPENF_NEW				= 0x0001,
	MCIWNDF_NOAUTOSIZEWINDOW	= 0x0001,
	MCIWNDF_NOPLAYBAR			= 0x0002,
	MCIWNDF_NOAUTOSIZEMOVIE		= 0x0004,
	MCIWNDF_NOMENU				= 0x0008,
	MCIWNDF_SHOWNAME			= 0x0010,
	MCIWNDF_SHOWPOS				= 0x0020,
	MCIWNDF_SHOWMODE			= 0x0040,
	MCIWNDF_SHOWALL				= 0x0070,
	MCIWNDF_NOTIFYMODE			= 0x0100,
	MCIWNDF_NOTIFYPOS			= 0x0200,
	MCIWNDF_NOTIFYSIZE			= 0x0400,
	MCIWNDF_NOTIFYERROR			= 0x1000,
	MCIWNDF_NOTIFYALL			= 0x1F00,
	MCIWNDF_NOTIFYANSI			= 0x0080,
	MCIWNDF_NOTIFYMEDIAA		= 0x0880,
	MCIWNDF_NOTIFYMEDIAW		= 0x0800,
}

version(Unicode) {
	alias MCIWNDF_NOTIFYMEDIAW	MCIWNDF_NOTIFYMEDIA;
} else { // Unicode
	alias MCIWNDF_NOTIFYMEDIAA	MCIWNDF_NOTIFYMEDIA;
}

enum {
	MCIWNDF_RECORD		= 0x2000,
	MCIWNDF_NOERRORDLG	= 0x4000,
	MCIWNDF_NOOPEN		= 0x8000,
}

// can macros

BOOL MCIWndCanPlay(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_PLAY, 0, 0); }
BOOL MCIWndCanRecord(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_RECORD, 0, 0); }
BOOL MCIWndCanSave(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_SAVE, 0, 0); }
BOOL MCIWndCanWindow(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_WINDOW, 0, 0); }
BOOL MCIWndCanEject(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_EJECT, 0, 0); }
BOOL MCIWndCanConfig(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_CONFIG, 0, 0); }
BOOL MCIWndPaletteKick(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_PALETTEKICK, 0, 0); }
LONG MCIWndSave(HWND hwnd, LPVOID szFile)
	{ return cast(LONG)SendMessage(hwnd, MCI_SAVE, 0, cast(LPARAM)szFile); }
LONG MCIWndSaveDialog(HWND hwnd)
	{ return MCIWndSave(hwnd, cast(LPVOID)-1); }
LONG MCIWndNew(HWND hwnd, LPVOID lp)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_NEW, 0, cast(LPARAM)lp); }
LONG MCIWndRecord(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCI_RECORD, 0, 0); }
LONG MCIWndOpen(HWND hwnd, LPVOID sz, UINT f)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_OPEN, cast(WPARAM)f, cast(LPARAM)sz); }
LONG MCIWndOpenDialog(HWND hwnd)
	{ return MCIWndOpen(hwnd, cast(LPVOID)-1, 0); }
LONG MCIWndClose(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCI_CLOSE, 0, 0); }
LONG MCIWndPlay(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCI_PLAY, 0, 0); }
LONG MCIWndStop(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCI_STOP, 0, 0); }
LONG MCIWndPause(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCI_PAUSE, 0, 0); }
LONG MCIWndResume(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCI_RESUME, 0, 0); }
LONG MCIWndSeek(HWND hwnd, LONG lPos)
	{ return cast(LONG)SendMessage(hwnd, MCI_SEEK, 0, cast(LPARAM)lPos); }
LONG MCIWndHome(HWND hwnd)
	{ return MCIWndSeek(hwnd, MCIWND_START); }
LONG MCIWndEnd(HWND hwnd)
	{ return MCIWndSeek(hwnd, MCIWND_END); }
LONG MCIWndEject(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_EJECT, 0, 0); }
LONG MCIWndGetSource(HWND hwnd, LPRECT prc)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GET_SOURCE, 0, cast(LPARAM)prc); }
LONG MCIWndPutSource(HWND hwnd, LPRECT prc)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_PUT_SOURCE, 0, cast(LPARAM)prc); }
LONG MCIWndGetDest(HWND hwnd, LPRECT prc)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GET_DEST, 0, cast(LPARAM)prc); }
LONG MCIWndPutDest(HWND hwnd, LPRECT prc)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_PUT_DEST, 0, cast(LPARAM)prc); }
LONG MCIWndPlayReverse(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_PLAYREVERSE, 0, 0); }
LONG MCIWndPlayFrom(HWND hwnd, LONG lPos)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_PLAYFROM, 0, cast(LPARAM)lPos); }
LONG MCIWndPlayTo(HWND hwnd, LONG lPos)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_PLAYTO, 0, cast(LPARAM)lPos); }
LONG MCIWndPlayFromTo(HWND hwnd, LONG lStart, LONG lEnd)
	{ MCIWndSeek(hwnd, lStart); return MCIWndPlayTo(hwnd, lEnd); }
UINT MCIWndGetDeviceID(HWND hwnd)
	{ return cast(UINT)SendMessage(hwnd, MCIWNDM_GETDEVICEID, 0, 0); }
UINT MCIWndGetAlias(HWND hwnd)
	{ return cast(UINT)SendMessage(hwnd, MCIWNDM_GETALIAS, 0, 0); }
LONG MCIWndGetMode(HWND hwnd, LPTSTR lp, UINT len)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETMODE, cast(WPARAM)len, cast(LPARAM)lp); }
LONG MCIWndGetPosition(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETPOSITION, 0, 0); }
LONG MCIWndGetPositionString(HWND hwnd, LPTSTR lp, UINT len)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETPOSITION, cast(WPARAM)len, cast(LPARAM)lp); }
LONG MCIWndGetStart(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETSTART, 0, 0); }
LONG MCIWndGetLength(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETLENGTH, 0, 0); }
LONG MCIWndGetEnd(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETEND, 0, 0); }
LONG MCIWndStep(HWND hwnd, LONG n)
	{ return cast(LONG)SendMessage(hwnd, MCI_STEP, 0, cast(LPARAM)n); }
void MCIWndDestroy(HWND hwnd)
	{ SendMessage(hwnd, WM_CLOSE, 0, 0); }
void MCIWndSetZoom(HWND hwnd, UINT iZoom)
	{ SendMessage(hwnd, MCIWNDM_SETZOOM, 0, cast(LPARAM)iZoom); }
UINT MCIWndGetZoom(HWND hwnd)
	{ return cast(UINT)SendMessage(hwnd, MCIWNDM_GETZOOM, 0, 0); }
LONG MCIWndSetVolume(HWND hwnd, UINT iVol)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_SETVOLUME, 0, cast(LPARAM)iVol); }
LONG MCIWndGetVolume(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETVOLUME, 0, 0); }
LONG MCIWndSetSpeed(HWND hwnd, UINT iSpeed)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_SETSPEED, 0, cast(LPARAM)iSpeed); }
LONG MCIWndGetSpeed(HWND hwnd)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETSPEED, 0, 0); }
LONG MCIWndSetTimeFormat(HWND hwnd, LPTSTR lp)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_SETTIMEFORMAT, 0, cast(LPARAM)lp); }
LONG MCIWndUseFrames(HWND hwnd)
	{ return MCIWndSetTimeFormat(hwnd, (cast(TCHAR[])"frames").ptr); }
LONG MCIWndUseTime(HWND hwnd)
	{ return MCIWndSetTimeFormat(hwnd, (cast(TCHAR[])"ms").ptr); }
LONG MCIWndGetTimeFormat(HWND hwnd, LPTSTR lp, UINT len)
	{ return cast(LONG)SendMessage(hwnd, MCIWNDM_GETTIMEFORMAT, cast(WPARAM)len, cast(LPARAM)lp); }
void MCIWndValidateMedia(HWND hwnd)
	{ SendMessage(hwnd, MCIWNDM_VALIDATEMEDIA, 0, 0); }
void MCIWndSetRepeat(HWND hwnd, BOOL f)
	{ SendMessage(hwnd, MCIWNDM_SETREPEAT, 0, cast(LPARAM)f); }
BOOL MCIWndGetRepeat(HWND hwnd)
	{ return cast(BOOL)SendMessage(hwnd, MCIWNDM_GETREPEAT, 0, 0); }
void MCIWndSetActiveTimer(HWND hwnd, UINT active)
	{ SendMessage(hwnd, MCIWNDM_SETACTIVETIMER, cast(WPARAM)active, 0); }
void MCIWndSetInactiveTimer(HWND hwnd, UINT inactive)
	{ SendMessage(hwnd, MCIWNDM_SETINACTIVETIMER, cast(WPARAM)inactive, 0); }
void MCIWndSetTimers(HWND hwnd, UINT active, UINT inactive)
	{ SendMessage(hwnd, MCIWNDM_SETTIMERS, cast(WPARAM)active, cast(LPARAM)inactive); }
UINT MCIWndGetActiveTimer(HWND hwnd)
	{ return cast(UINT)SendMessage(hwnd, MCIWNDM_GETACTIVETIMER, 0, 0); }
UINT MCIWndGetInactiveTimer(HWND hwnd)
	{ return cast(UINT)SendMessage(hwnd, MCIWNDM_GETINACTIVETIMER, 0, 0); }
LONG MCIWndRealize(HWND hwnd, BOOL fBkgnd)
	{ return SendMessage(hwnd, MCIWNDM_REALIZE, cast(WPARAM)fBkgnd, 0); }
LONG MCIWndSendString(HWND hwnd, LPTSTR sz)
	{ return SendMessage(hwnd, MCIWNDM_SENDSTRING, 0, cast(LPARAM)sz); }
LONG MCIWndReturnString(HWND hwnd, LPVOID lp, UINT len)
	{ return SendMessage(hwnd, MCIWNDM_RETURNSTRING, cast(WPARAM)len, cast(LPARAM)lp); }
LONG MCIWndGetError(HWND hwnd, LPVOID lp, UINT len)
	{ return SendMessage(hwnd, MCIWNDM_GETERROR, cast(WPARAM)len, cast(LPARAM)lp); }
HPALETTE MCIWndGetPalette(HWND hwnd)
	{ return cast(HPALETTE)SendMessage(hwnd, MCIWNDM_GETPALETTE, 0, 0); }
LONG MCIWndSetPalette(HWND hwnd, HPALETTE hpal)
	{ return SendMessage(hwnd, MCIWNDM_SETPALETTE, cast(WPARAM)hpal, 0); }
LONG MCIWndGetFileName(HWND hwnd, LPVOID lp, UINT len)
	{ return SendMessage(hwnd, MCIWNDM_GETFILENAME, cast(WPARAM)len, cast(LPARAM)lp); }
LONG MCIWndGetDevice(HWND hwnd, LPVOID lp, UINT len)
	{ return SendMessage(hwnd, MCIWNDM_GETDEVICE, cast(WPARAM)len, cast(LPARAM)lp); }
UINT MCIWndGetStyles(HWND hwnd)
	{ return SendMessage(hwnd, MCIWNDM_GETSTYLES, 0, 0); }
LONG MCIWndChangeStyles(HWND hwnd, UINT mask, LONG value)
	{ return SendMessage(hwnd, MCIWNDM_CHANGESTYLES, cast(WPARAM)mask, cast(LPARAM)value); }
LONG MCIWndOpenInterface(HWND hwnd, LPUNKNOWN pUnk)
	{ return SendMessage(hwnd, MCIWNDM_OPENINTERFACE, 0, cast(LPARAM)cast(void*)pUnk); }
LONG MCIWndSetOwner(HWND hwnd, HWND hwndP)
	{ return SendMessage(hwnd, MCIWNDM_SETOWNER, cast(WPARAM)hwndP, 0); }

enum {
	MCIWNDM_GETDEVICEID			= WM_USER + 100,
	MCIWNDM_SENDSTRINGA			= WM_USER + 101,
	MCIWNDM_GETPOSITIONA		= WM_USER + 102,
	MCIWNDM_GETSTART			= WM_USER + 103,
	MCIWNDM_GETLENGTH			= WM_USER + 104,
	MCIWNDM_GETEND				= WM_USER + 105,
	MCIWNDM_GETMODEA			= WM_USER + 106,
	MCIWNDM_EJECT				= WM_USER + 107,
	MCIWNDM_SETZOOM				= WM_USER + 108,
	MCIWNDM_GETZOOM				= WM_USER + 109,
	MCIWNDM_SETVOLUME			= WM_USER + 110,
	MCIWNDM_GETVOLUME			= WM_USER + 111,
	MCIWNDM_SETSPEED			= WM_USER + 112,
	MCIWNDM_GETSPEED			= WM_USER + 113,
	MCIWNDM_SETREPEAT			= WM_USER + 114,
	MCIWNDM_GETREPEAT			= WM_USER + 115,
	MCIWNDM_REALIZE				= WM_USER + 118,
	MCIWNDM_SETTIMEFORMATA		= WM_USER + 119,
	MCIWNDM_GETTIMEFORMATA		= WM_USER + 120,
	MCIWNDM_VALIDATEMEDIA		= WM_USER + 121,
	MCIWNDM_PLAYFROM			= WM_USER + 122,
	MCIWNDM_PLAYTO				= WM_USER + 123,
	MCIWNDM_GETFILENAMEA		= WM_USER + 124,
	MCIWNDM_GETDEVICEA			= WM_USER + 125,
	MCIWNDM_GETPALETTE			= WM_USER + 126,
	MCIWNDM_SETPALETTE			= WM_USER + 127,
	MCIWNDM_GETERRORA			= WM_USER + 128,
	MCIWNDM_SETTIMERS			= WM_USER + 129,
	MCIWNDM_SETACTIVETIMER		= WM_USER + 130,
	MCIWNDM_SETINACTIVETIMER	= WM_USER + 131,
	MCIWNDM_GETACTIVETIMER		= WM_USER + 132,
	MCIWNDM_GETINACTIVETIMER	= WM_USER + 133,
	MCIWNDM_NEWA				= WM_USER + 134,
	MCIWNDM_CHANGESTYLES		= WM_USER + 135,
	MCIWNDM_GETSTYLES			= WM_USER + 136,
	MCIWNDM_GETALIAS			= WM_USER + 137,
	MCIWNDM_RETURNSTRINGA		= WM_USER + 138,
	MCIWNDM_PLAYREVERSE			= WM_USER + 139,
	MCIWNDM_GET_SOURCE			= WM_USER + 140,
	MCIWNDM_PUT_SOURCE			= WM_USER + 141,
	MCIWNDM_GET_DEST			= WM_USER + 142,
	MCIWNDM_PUT_DEST			= WM_USER + 143,
	MCIWNDM_CAN_PLAY			= WM_USER + 144,
	MCIWNDM_CAN_WINDOW			= WM_USER + 145,
	MCIWNDM_CAN_RECORD			= WM_USER + 146,
	MCIWNDM_CAN_SAVE			= WM_USER + 147,
	MCIWNDM_CAN_EJECT			= WM_USER + 148,
	MCIWNDM_CAN_CONFIG			= WM_USER + 149,
	MCIWNDM_PALETTEKICK			= WM_USER + 150,
	MCIWNDM_OPENINTERFACE		= WM_USER + 151,
	MCIWNDM_SETOWNER			= WM_USER + 152,
	MCIWNDM_OPENA				= WM_USER + 153,
	MCIWNDM_SENDSTRINGW			= WM_USER + 201,
	MCIWNDM_GETPOSITIONW		= WM_USER + 202,
	MCIWNDM_GETMODEW			= WM_USER + 206,
	MCIWNDM_SETTIMEFORMATW		= WM_USER + 219,
	MCIWNDM_GETTIMEFORMATW		= WM_USER + 220,
	MCIWNDM_GETFILENAMEW		= WM_USER + 224,
	MCIWNDM_GETDEVICEW			= WM_USER + 225,
	MCIWNDM_GETERRORW			= WM_USER + 228,
	MCIWNDM_NEWW				= WM_USER + 234,
	MCIWNDM_RETURNSTRINGW		= WM_USER + 238,
	MCIWNDM_OPENW				= WM_USER + 252,
}

version(Unicode) {
	alias MCIWNDM_SENDSTRINGW		MCIWNDM_SENDSTRING;
	alias MCIWNDM_GETPOSITIONW		MCIWNDM_GETPOSITION;
	alias MCIWNDM_GETMODEW			MCIWNDM_GETMODE;
	alias MCIWNDM_SETTIMEFORMATW	MCIWNDM_SETTIMEFORMAT;
	alias MCIWNDM_GETTIMEFORMATW	MCIWNDM_GETTIMEFORMAT;
	alias MCIWNDM_GETFILENAMEW		MCIWNDM_GETFILENAME;
	alias MCIWNDM_GETDEVICEW		MCIWNDM_GETDEVICE;
	alias MCIWNDM_GETERRORW			MCIWNDM_GETERROR;
	alias MCIWNDM_NEWW				MCIWNDM_NEW;
	alias MCIWNDM_RETURNSTRINGW		MCIWNDM_RETURNSTRING;
	alias MCIWNDM_OPENW				MCIWNDM_OPEN;
} else { // Unicode
	alias MCIWNDM_SENDSTRINGA		MCIWNDM_SENDSTRING;
	alias MCIWNDM_GETPOSITIONA		MCIWNDM_GETPOSITION;
	alias MCIWNDM_GETMODEA			MCIWNDM_GETMODE;
	alias MCIWNDM_SETTIMEFORMATA	MCIWNDM_SETTIMEFORMAT;
	alias MCIWNDM_GETTIMEFORMATA	MCIWNDM_GETTIMEFORMAT;
	alias MCIWNDM_GETFILENAMEA		MCIWNDM_GETFILENAME;
	alias MCIWNDM_GETDEVICEA		MCIWNDM_GETDEVICE;
	alias MCIWNDM_GETERRORA			MCIWNDM_GETERROR;
	alias MCIWNDM_NEWA				MCIWNDM_NEW;
	alias MCIWNDM_RETURNSTRINGA		MCIWNDM_RETURNSTRING;
	alias MCIWNDM_OPENA				MCIWNDM_OPEN;
}

enum {
	MCIWNDM_NOTIFYMODE	= WM_USER + 200,
	MCIWNDM_NOTIFYPOS	= WM_USER + 201,
	MCIWNDM_NOTIFYSIZE	= WM_USER + 202,
	MCIWNDM_NOTIFYMEDIA	= WM_USER + 203,
	MCIWNDM_NOTIFYERROR	= WM_USER + 205,
}

const MCIWND_START	= -1;
const MCIWND_END	= -2;

enum {
	MCI_CLOSE	= 0x0804,
	MCI_PLAY	= 0x0806,
	MCI_SEEK	= 0x0807,
	MCI_STOP	= 0x0808,
	MCI_PAUSE	= 0x0809,
	MCI_STEP	= 0x080E,
	MCI_RECORD	= 0x080F,
	MCI_SAVE	= 0x0813,
	MCI_CUT		= 0x0851,
	MCI_COPY	= 0x0852,
	MCI_PASTE	= 0x0853,
	MCI_RESUME	= 0x0855,
	MCI_DELETE	= 0x0856,
}

enum {
	MCI_MODE_NOT_READY	= 524,
	MCI_MODE_STOP,
	MCI_MODE_PLAY,
	MCI_MODE_RECORD,
	MCI_MODE_SEEK,
	MCI_MODE_PAUSE,
	MCI_MODE_OPEN,
}

typedef HANDLE HVIDEO;
alias HVIDEO* LPHVIDEO;

// Error Return Values

enum {
	DV_ERR_OK				= 0,
	DV_ERR_BASE				= 1,
	DV_ERR_NONSPECIFIC		= DV_ERR_BASE,
	DV_ERR_BADFORMAT		= DV_ERR_BASE + 1,
	DV_ERR_STILLPLAYING		= DV_ERR_BASE + 2,
	DV_ERR_UNPREPARED		= DV_ERR_BASE + 3,
	DV_ERR_SYNC				= DV_ERR_BASE + 4,
	DV_ERR_TOOMANYCHANNELS	= DV_ERR_BASE + 5,
	DV_ERR_NOTDETECTED		= DV_ERR_BASE + 6,
	DV_ERR_BADINSTALL		= DV_ERR_BASE + 7,
	DV_ERR_CREATEPALETTE	= DV_ERR_BASE + 8,
	DV_ERR_SIZEFIELD		= DV_ERR_BASE + 9,
	DV_ERR_PARAM1			= DV_ERR_BASE + 10,
	DV_ERR_PARAM2			= DV_ERR_BASE + 11,
	DV_ERR_CONFIG1			= DV_ERR_BASE + 12,
	DV_ERR_CONFIG2			= DV_ERR_BASE + 13,
	DV_ERR_FLAGS			= DV_ERR_BASE + 14,
	DV_ERR_13				= DV_ERR_BASE + 15,
	DV_ERR_NOTSUPPORTED		= DV_ERR_BASE + 16,
	DV_ERR_NOMEM			= DV_ERR_BASE + 17,
	DV_ERR_ALLOCATED		= DV_ERR_BASE + 18,
	DV_ERR_BADDEVICEID		= DV_ERR_BASE + 19,
	DV_ERR_INVALHANDLE		= DV_ERR_BASE + 20,
	DV_ERR_BADERRNUM		= DV_ERR_BASE + 21,
	DV_ERR_NO_BUFFERS		= DV_ERR_BASE + 22,
	DV_ERR_MEM_CONFLICT		= DV_ERR_BASE + 23,
	DV_ERR_IO_CONFLICT		= DV_ERR_BASE + 24,
	DV_ERR_DMA_CONFLICT		= DV_ERR_BASE + 25,
	DV_ERR_INT_CONFLICT		= DV_ERR_BASE + 26,
	DV_ERR_PROTECT_ONLY		= DV_ERR_BASE + 27,
	DV_ERR_LASTERROR		= DV_ERR_BASE + 27,
	DV_ERR_USER_MSG			= DV_ERR_BASE + 1000,
}

// Callback Messages

enum {
	MM_DRVM_OPEN	= 0x3D0,
	MM_DRVM_CLOSE,
	MM_DRVM_DATA,
	MM_DRVM_ERROR,
}

enum {
	DV_VM_OPEN	= MM_DRVM_OPEN,
	DV_VM_CLOSE	= MM_DRVM_CLOSE,
	DV_VM_DATA	= MM_DRVM_DATA,
	DV_VM_ERROR	= MM_DRVM_ERROR,
}

/**
 * Structures
 */

struct VIDEOHDR {
	LPBYTE		lpData;
	DWORD		dwBufferLength;
	DWORD		dwBytesUsed;
	DWORD		dwTimeCaptured;
	DWORD_PTR	dwUser;
	DWORD		dwFlags;
    DWORD_PTR   dwReserved[4];
}
alias VIDEOHDR* PVIDEOHDR, LPVIDEOHDR;

enum {
	VHDR_DONE		= 0x00000001,
	VHDR_PREPARED	= 0x00000002,
	VHDR_INQUEUE	= 0x00000004,
	VHDR_KEYFRAME	= 0x00000008,
	VHDR_VALID		= 0x0000000F,
}

struct CHANNEL_CAPS {
	DWORD	dwFlags;
	DWORD	dwSrcRectXMod;
	DWORD	dwSrcRectYMod;
	DWORD	dwSrcRectWidthMod;
	DWORD	dwSrcRectHeightMod;
	DWORD	dwDstRectXMod;
	DWORD	dwDstRectYMod;
	DWORD	dwDstRectWidthMod;
	DWORD	dwDstRectHeightMod;
}
alias CHANNEL_CAPS* PCHANNEL_CAPS, LPCHANNEL_CAPS;

enum {
	VCAPS_OVERLAY		= 0x00000001,
	VCAPS_SRC_CAN_CLIP	= 0x00000002,
	VCAPS_DST_CAN_CLIP	= 0x00000004,
	VCAPS_CAN_SCALE		= 0x00000008,
}

/**
 * API Flags
 */

enum {
	VIDEO_EXTERNALIN			= 0x0001,
	VIDEO_EXTERNALOUT			= 0x0002,
	VIDEO_IN					= 0x0004,
	VIDEO_OUT					= 0x0008,
	VIDEO_DLG_QUERY				= 0x0010,
}

enum {
	VIDEO_CONFIGURE_QUERYSIZE	= 0x0001,
	VIDEO_CONFIGURE_CURRENT		= 0x0010,
	VIDEO_CONFIGURE_NOMINAL		= 0x0020,
	VIDEO_CONFIGURE_MIN			= 0x0040,
	VIDEO_CONFIGURE_MAX			= 0x0080,
	VIDEO_CONFIGURE_SET			= 0x1000,
	VIDEO_CONFIGURE_GET			= 0x2000,
	VIDEO_CONFIGURE_QUERY		= 0x8000,
}

/**
 * CONFIGURE MESSAGES
 */

enum {
	DVM_USER			= 0x4000,
	DVM_CONFIGURE_START	= 0x1000,
	DVM_CONFIGURE_END	= 0x1FFF,
	DVM_PALETTE			= DVM_CONFIGURE_START + 1,
	DVM_FORMAT			= DVM_CONFIGURE_START + 2,
	DVM_PALETTERGB555	= DVM_CONFIGURE_START + 3,
	DVM_SRC_RECT		= DVM_CONFIGURE_START + 4,
	DVM_DST_RECT		= DVM_CONFIGURE_START + 5,
}

/**
 * AVICap window class
 */

LRESULT AVICapSM(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	if (IsWindow(hWnd)) {
		return SendMessage(hWnd, msg, wParam, lParam);
	}
	return 0;
}

enum {
	WM_CAP_START				= WM_USER,
	WM_CAP_UNICODE_START		= WM_USER + 100,

	WM_CAP_GET_CAPSTREAMPTR		= WM_CAP_START + 1,
	WM_CAP_SET_CALLBACK_ERRORA	= WM_CAP_START + 2,
	WM_CAP_SET_CALLBACK_STATUSA	= WM_CAP_START + 3,

	WM_CAP_SET_CALLBACK_ERRORW	= WM_CAP_UNICODE_START + 2,
	WM_CAP_SET_CALLBACK_STATUSW	= WM_CAP_UNICODE_START + 3,
}

version(Unicode) {
	alias WM_CAP_SET_CALLBACK_ERRORW	WM_CAP_SET_CALLBACK_ERROR;
	alias WM_CAP_SET_CALLBACK_STATUSW	WM_CAP_SET_CALLBACK_STATUS;
} else { // Unicode
	alias WM_CAP_SET_CALLBACK_ERRORA	WM_CAP_SET_CALLBACK_ERROR;
	alias WM_CAP_SET_CALLBACK_STATUSA	WM_CAP_SET_CALLBACK_STATUS;
}

enum {
	WM_CAP_SET_CALLBACK_YIELD		= WM_CAP_START + 4,
	WM_CAP_SET_CALLBACK_FRAME		= WM_CAP_START + 5,
	WM_CAP_SET_CALLBACK_VIDEOSTREAM	= WM_CAP_START + 6,
	WM_CAP_SET_CALLBACK_WAVESTREAM	= WM_CAP_START + 7,
	WM_CAP_GET_USER_DATA			= WM_CAP_START + 8,
	WM_CAP_SET_USER_DATA			= WM_CAP_START + 9,
	WM_CAP_DRIVER_CONNECT			= WM_CAP_START + 10,
	WM_CAP_DRIVER_DISCONNECT		= WM_CAP_START + 11,
	WM_CAP_DRIVER_GET_NAMEA			= WM_CAP_START + 12,
	WM_CAP_DRIVER_GET_VERSIONA		= WM_CAP_START + 13,

	WM_CAP_DRIVER_GET_NAMEW			= WM_CAP_UNICODE_START + 12,
	WM_CAP_DRIVER_GET_VERSIONW		= WM_CAP_UNICODE_START + 13,
}

version(Unicode) {
	alias WM_CAP_DRIVER_GET_NAMEW		WM_CAP_DRIVER_GET_NAME;
	alias WM_CAP_DRIVER_GET_VERSIONW	WM_CAP_DRIVER_GET_VERSION;
} else { // Unicode
	alias WM_CAP_DRIVER_GET_NAMEA		WM_CAP_DRIVER_GET_NAME;
	alias WM_CAP_DRIVER_GET_VERSIONA	WM_CAP_DRIVER_GET_VERSION;
}

enum {
	WM_CAP_DRIVER_GET_CAPS			= WM_CAP_START + 14,
	WM_CAP_FILE_SET_CAPTURE_FILEA	= WM_CAP_START + 20,
	WM_CAP_FILE_GET_CAPTURE_FILEA	= WM_CAP_START + 21,
	WM_CAP_FILE_SAVEASA				= WM_CAP_START + 23,
	WM_CAP_FILE_SAVEDIBA			= WM_CAP_START + 25,

	WM_CAP_FILE_SET_CAPTURE_FILEW	= WM_CAP_UNICODE_START + 20,
	WM_CAP_FILE_GET_CAPTURE_FILEW	= WM_CAP_UNICODE_START + 21,
	WM_CAP_FILE_SAVEASW				= WM_CAP_UNICODE_START + 23,
	WM_CAP_FILE_SAVEDIBW			= WM_CAP_UNICODE_START + 25,
}

version(Unicode) {
	alias WM_CAP_FILE_SET_CAPTURE_FILEW	WM_CAP_FILE_SET_CAPTURE_FILE;
	alias WM_CAP_FILE_GET_CAPTURE_FILEW	WM_CAP_FILE_GET_CAPTURE_FILE;
	alias WM_CAP_FILE_SAVEASW			WM_CAP_FILE_SAVEAS;
	alias WM_CAP_FILE_SAVEDIBW			WM_CAP_FILE_SAVEDIB;
} else { // Unicode
	alias WM_CAP_FILE_SET_CAPTURE_FILEA	WM_CAP_FILE_SET_CAPTURE_FILE;
	alias WM_CAP_FILE_GET_CAPTURE_FILEA	WM_CAP_FILE_GET_CAPTURE_FILE;
	alias WM_CAP_FILE_SAVEASA			WM_CAP_FILE_SAVEAS;
	alias WM_CAP_FILE_SAVEDIBA			WM_CAP_FILE_SAVEDIB;
}

enum {
	WM_CAP_FILE_ALLOCATE		= WM_CAP_START + 22,
	WM_CAP_FILE_SET_INFOCHUNK	= WM_CAP_START + 24,
	WM_CAP_EDIT_COPY			= WM_CAP_START + 30,
	WM_CAP_SET_AUDIOFORMAT		= WM_CAP_START + 35,
	WM_CAP_GET_AUDIOFORMAT		= WM_CAP_START + 36,
	WM_CAP_DLG_VIDEOFORMAT		= WM_CAP_START + 41,
	WM_CAP_DLG_VIDEOSOURCE		= WM_CAP_START + 42,
	WM_CAP_DLG_VIDEODISPLAY		= WM_CAP_START + 43,
	WM_CAP_GET_VIDEOFORMAT		= WM_CAP_START + 44,
	WM_CAP_SET_VIDEOFORMAT		= WM_CAP_START + 45,
	WM_CAP_DLG_VIDEOCOMPRESSION	= WM_CAP_START + 46,
	WM_CAP_SET_PREVIEW			= WM_CAP_START + 50,
	WM_CAP_SET_OVERLAY			= WM_CAP_START + 51,
	WM_CAP_SET_PREVIEWRATE		= WM_CAP_START + 52,
	WM_CAP_SET_SCALE			= WM_CAP_START + 53,
	WM_CAP_GET_STATUS			= WM_CAP_START + 54,
	WM_CAP_SET_SCROLL			= WM_CAP_START + 55,
	WM_CAP_GRAB_FRAME			= WM_CAP_START + 60,
	WM_CAP_GRAB_FRAME_NOSTOP	= WM_CAP_START + 61,
	WM_CAP_SEQUENCE				= WM_CAP_START + 62,
	WM_CAP_SEQUENCE_NOFILE		= WM_CAP_START + 63,
	WM_CAP_SET_SEQUENCE_SETUP	= WM_CAP_START + 64,
	WM_CAP_GET_SEQUENCE_SETUP	= WM_CAP_START + 65,
	WM_CAP_SET_MCI_DEVICEA		= WM_CAP_START + 66,
	WM_CAP_GET_MCI_DEVICEA		= WM_CAP_START + 67,

	WM_CAP_SET_MCI_DEVICEW		= WM_CAP_UNICODE_START + 66,
	WM_CAP_GET_MCI_DEVICEW		= WM_CAP_UNICODE_START + 67,
}

version(Unicode) {
	alias WM_CAP_SET_MCI_DEVICEW	WM_CAP_SET_MCI_DEVICE;
	alias WM_CAP_GET_MCI_DEVICEW	WM_CAP_GET_MCI_DEVICE;
} else { // Unicode
	alias WM_CAP_SET_MCI_DEVICEA	WM_CAP_SET_MCI_DEVICE;
	alias WM_CAP_GET_MCI_DEVICEA	WM_CAP_GET_MCI_DEVICE;
}

enum {
	WM_CAP_STOP					= WM_CAP_START + 68,
	WM_CAP_ABORT				= WM_CAP_START + 69,
	WM_CAP_SINGLE_FRAME_OPEN	= WM_CAP_START + 70,
	WM_CAP_SINGLE_FRAME_CLOSE	= WM_CAP_START + 71,
	WM_CAP_SINGLE_FRAME			= WM_CAP_START + 72,
	WM_CAP_PAL_OPENA			= WM_CAP_START + 80,
	WM_CAP_PAL_SAVEA			= WM_CAP_START + 81,

	WM_CAP_PAL_OPENW			= WM_CAP_UNICODE_START + 80,
	WM_CAP_PAL_SAVEW			= WM_CAP_UNICODE_START + 81,
}

version(Unicode) {
	alias WM_CAP_PAL_OPENW	WM_CAP_PAL_OPEN;
	alias WM_CAP_PAL_SAVEW	WM_CAP_PAL_SAVE;
} else { // Unicode
	alias WM_CAP_PAL_OPENA	WM_CAP_PAL_OPEN;
	alias WM_CAP_PAL_SAVEA	WM_CAP_PAL_SAVE;
}

enum {
	WM_CAP_PAL_PASTE				= WM_CAP_START + 82,
	WM_CAP_PAL_AUTOCREATE			= WM_CAP_START + 83,
	WM_CAP_PAL_MANUALCREATE			= WM_CAP_START + 84,
	WM_CAP_SET_CALLBACK_CAPCONTROL	= WM_CAP_START + 85,
	WM_CAP_UNICODE_END				= WM_CAP_PAL_SAVEW,
	WM_CAP_END						= WM_CAP_UNICODE_END,
}

/**
 * message wrapper
 */

BOOL capSetCallbackOnError(HWND hWnd, LPVOID fpProc)				{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_ERROR, 0, cast(LPARAM)fpProc); }
BOOL capSetCallbackOnStatus(HWND hWnd, LPVOID fpProc)				{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_STATUS, 0, cast(LPARAM)fpProc); }
BOOL capSetCallbackOnYield(HWND hWnd, LPVOID fpProc)				{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_YIELD, 0, cast(LPARAM)fpProc); }
BOOL capSetCallbackOnFrame(HWND hWnd, LPVOID fpProc)				{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_FRAME, 0, cast(LPARAM)fpProc); }
BOOL capSetCallbackOnVideoStream(HWND hWnd, LPVOID fpProc)			{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, cast(LPARAM)fpProc); }
BOOL capSetCallbackOnWaveStream(HWND hWnd, LPVOID fpProc)			{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_WAVESTREAM, 0, cast(LPARAM)fpProc); }
BOOL capSetCallbackOnCapControl(HWND hWnd, LPVOID fpProc)			{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_CAPCONTROL, 0, cast(LPARAM)fpProc); }

BOOL capSetUserData(HWND hWnd, LPARAM lUser)						{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_USER_DATA, 0, lUser); }
BOOL capGetUserData(HWND hWnd)										{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_USER_DATA, 0, 0); }

BOOL capDriverConnect(HWND hWnd, WPARAM i)							{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_CONNECT, i, 0); }
BOOL capDriverDisconnect(HWND hWnd)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_DISCONNECT, 0, 0); }
BOOL capDriverGetName(HWND hWnd, LPTSTR szName, WPARAM wSize)		{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_GET_NAME, wSize, cast(LPARAM)szName); }
BOOL capDriverGetVersion(HWND hWnd, LPTSTR szVer, WPARAM wSize)		{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_GET_VERSION, wSize, cast(LPARAM)szVer); }
BOOL capDriverGetCaps(HWND hWnd, LPCAPDRIVERCAPS s, WPARAM wSize)	{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_GET_CAPS, wSize, cast(LPARAM)s); }

BOOL capFileSetCaptureFile(HWND hWnd, LPTSTR szName)				{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SET_CAPTURE_FILE, 0, cast(LPARAM)szName); }
BOOL capFileGetCaptureFile(HWND hWnd, LPTSTR szName, WPARAM wSize)	{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_GET_CAPTURE_FILE, wSize, cast(LPARAM)szName); }
BOOL capFileAlloc(HWND hWnd, WPARAM wSize)							{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_ALLOCATE, wSize, 0); }
BOOL capFileSaveAs(HWND hWnd, LPTSTR szName)						{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SAVEAS, 0, cast(LPARAM)szName); }
BOOL capFileSetInfoChunk(HWND hWnd, LPCAPINFOCHUNK lpInfoChunk)		{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SET_INFOCHUNK, 0, cast(LPARAM)lpInfoChunk); }
BOOL capFileSaveDIB(HWND hWnd, LPTSTR szName)						{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SAVEDIB, 0, cast(LPARAM)szName); }

BOOL capEditCopy(HWND hWnd)											{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_EDIT_COPY, 0, 0); }

BOOL capSetAudioFormat(HWND hWnd, LPWAVEFORMATEX s, WPARAM wSize)	{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_AUDIOFORMAT, wSize, cast(LPARAM)s); }
DWORD capGetAudioFormat(HWND hWnd, LPWAVEFORMATEX s, WPARAM wSize)	{ return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_AUDIOFORMAT, wSize, cast(LPARAM)s); }
DWORD capGetAudioFormatSize(HWND hWnd)								{ return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_AUDIOFORMAT, 0, 0); }

BOOL capDlgVideoFormat(HWND hWnd)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEOFORMAT, 0, 0); }
BOOL capDlgVideoSource(HWND hWnd)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEOSOURCE, 0, 0); }
BOOL capDlgVideoDisplay(HWND hWnd)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEODISPLAY, 0, 0); }
BOOL capDlgVideoCompression(HWND hWnd)								{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEOCOMPRESSION, 0, 0); }

DWORD capGetVideoFormat(HWND hWnd, void* s, WPARAM wSize)			{ return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_VIDEOFORMAT, wSize, cast(LPARAM)s); }
DWORD capGetVideoFormatSize(HWND hWnd)								{ return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_VIDEOFORMAT, 0, 0); }
BOOL capSetVideoFormat(HWND hWnd, void* s, WPARAM wSize)			{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_VIDEOFORMAT, wSize, cast(LPARAM)s); }

BOOL capPreview(HWND hWnd, BOOL f)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_PREVIEW, cast(WPARAM)f, 0); }
BOOL capPreviewRate(HWND hWnd, WPARAM wMS)							{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_PREVIEWRATE, wMS, 0); }
BOOL capOverlay(HWND hWnd, BOOL f)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_OVERLAY, cast(WPARAM)f, 0); }
BOOL capPreviewScale(HWND hWnd, BOOL f)								{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_SCALE, cast(WPARAM)f, 0); }
BOOL capGetStatus(HWND hWnd, LPCAPSTATUS s, WPARAM wSize)			{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_STATUS, wSize, cast(LPARAM)s); }
BOOL capSetScrollPos(HWND hWnd, LPPOINT lpP)						{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_SCROLL, 0, cast(LPARAM)lpP); }

BOOL capGrabFrame(HWND hWnd)										{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_GRAB_FRAME, 0, 0); }
BOOL capGrabFrameNoStop(HWND hWnd)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0); }

BOOL capCaptureSequence(HWND hWnd)									{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SEQUENCE, 0, 0); }
BOOL capCaptureSequenceNoFile(HWND hWnd)							{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SEQUENCE_NOFILE, 0, 0); }
BOOL capCaptureStop(HWND hWnd)										{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_STOP, 0, 0); }
BOOL capCaptureAbort(HWND hWnd)										{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_ABORT, 0, 0); }

BOOL capCaptureSingleFrameOpen(HWND hWnd)							{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SINGLE_FRAME_OPEN, 0, 0); }
BOOL capCaptureSingleFrameClose(HWND hWnd)							{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SINGLE_FRAME_CLOSE, 0, 0); }
BOOL capCaptureSingleFrame(HWND hWnd)								{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SINGLE_FRAME, 0, 0); }

BOOL capCaptureGetSetup(HWND hWnd, LPCAPTUREPARMS s, WPARAM wSize)	{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_SEQUENCE_SETUP, wSize, cast(LPARAM)s); }
BOOL capCaptureSetSetup(HWND hWnd, LPCAPTUREPARMS s, WPARAM wSize)	{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_SEQUENCE_SETUP, wSize, cast(LPARAM)s); }

BOOL capSetMCIDeviceName(HWND hWnd, LPTSTR szName)					{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_MCI_DEVICE, 0, cast(LPARAM)szName); }
BOOL capGetMCIDeviceName(HWND hWnd, LPTSTR szName, WPARAM wSize)	{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_MCI_DEVICE, wSize, cast(LPARAM)szName); }

BOOL capPaletteOpen(HWND hWnd, LPTSTR szName)						{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_OPEN, 0, cast(LPARAM)szName); }
BOOL capPaletteSave(HWND hWnd, LPTSTR szName)						{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_SAVE, 0, cast(LPARAM)szName); }
BOOL capPalettePaste(HWND hWnd)										{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_PASTE, 0, 0); }
BOOL capPaletteAuto(HWND hWnd, WPARAM iFrames, LPARAM iColors)		{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_AUTOCREATE, iFrames, iColors); }
BOOL capPaletteManual(HWND hWnd, WPARAM fGrab, LPARAM iColors)		{ return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_MANUALCREATE, fGrab, iColors); }

/**
 * structs
 */

struct CAPDRIVERCAPS {
	UINT	wDeviceIndex;
	BOOL	fHasOverlay;
	BOOL	fHasDlgVideoSource;
	BOOL	fHasDlgVideoFormat;
	BOOL	fHasDlgVideoDisplay;
	BOOL	fCaptureInitialized;
	BOOL	fDriverSuppliesPalettes;
	HANDLE	hVideoIn;
	HANDLE	hVideoOut;
	HANDLE	hVideoExtIn;
	HANDLE	hVideoExtOut;
}
alias CAPDRIVERCAPS* PCAPDRIVERCAPS, LPCAPDRIVERCAPS;

struct CAPSTATUS {
	UINT		uiImageWidth;
	UINT		uiImageHeight;
	BOOL		fLiveWindow;
	BOOL		fOverlayWindow;
	BOOL		fScale;
	POINT		ptScroll;
	BOOL		fUsingDefaultPalette;
	BOOL		fAudioHardware;
	BOOL		fCapFileExists;
	DWORD		dwCurrentVideoFrame;
	DWORD		dwCurrentVideoFramesDropped;
	DWORD		dwCurrentWaveSamples;
	DWORD		dwCurrentTimeElapsedMS;
	HPALETTE	hPalCurrent;
	BOOL		fCapturingNow;
	DWORD		dwReturn;
	UINT		wNumVideoAllocated;
	UINT		wNumAudioAllocated;
}
alias CAPSTATUS* PCAPSTATUS, LPCAPSTATUS;

struct CAPTUREPARMS {
	DWORD	dwRequestMicroSecPerFrame;
	BOOL	fMakeUserHitOKToCapture;
	UINT	wPercentDropForError;
	BOOL	fYield;
	DWORD	dwIndexSize;
	UINT	wChunkGranularity;
	BOOL	fUsingDOSMemory;
	UINT	wNumVideoRequested;
	BOOL	fCaptureAudio;
	UINT	wNumAudioRequested;
	UINT	vKeyAbort;
	BOOL	fAbortLeftMouse;
	BOOL	fAbortRightMouse;
	BOOL	fLimitEnabled;
	UINT	wTimeLimit;
	BOOL	fMCIControl;
	BOOL	fStepMCIDevice;
	DWORD	dwMCIStartTime;
	DWORD	dwMCIStopTime;
	BOOL	fStepCaptureAt2x;
	UINT	wStepCaptureAverageFrames;
	DWORD	dwAudioBufferSize;
	BOOL	fDisableWriteCache;
	UINT	AVStreamMaster;
}
alias CAPTUREPARMS* PCAPTUREPARMS, LPCAPTUREPARMS;

const AVSTREAMMASTER_AUDIO = 0;
const AVSTREAMMASTER_NONE  = 1;

struct CAPINFOCHUNK {
	FOURCC	fccInfoID;
	LPVOID	lpData;
	LONG	cbData;
}
alias CAPINFOCHUNK* PCAPINFOCHUNK, LPCAPINFOCHUNK;

// Callback Definitions

extern (Windows) {
	alias LRESULT function(HWND hWnd) CAPYIELDCALLBACK;
	alias LRESULT function(HWND hWnd, int nID, LPCWSTR lpsz) CAPSTATUSCALLBACKW;
	alias LRESULT function(HWND hWnd, int nID, LPCWSTR lpsz) CAPERRORCALLBACKW;
	alias LRESULT function(HWND hWnd, int nID, LPCSTR lpsz) CAPSTATUSCALLBACKA;
	alias LRESULT function(HWND hWnd, int nID, LPCSTR lpsz) CAPERRORCALLBACKA;
}

version(Unicode) {
	alias CAPSTATUSCALLBACKW	CAPSTATUSCALLBACK;
	alias CAPERRORCALLBACKW		CAPERRORCALLBACK;
} else { // Unicode
	alias CAPSTATUSCALLBACKA	CAPSTATUSCALLBACK;
	alias CAPERRORCALLBACKA		CAPERRORCALLBACK;
}

extern (Windows) {
	alias LRESULT function(HWND hWnd, LPVIDEOHDR lpVHdr) CAPVIDEOCALLBACK;
	alias LRESULT function(HWND hWnd, LPWAVEHDR lpWHdr) CAPWAVECALLBACK;
	alias LRESULT function(HWND hWnd, int nState) CAPCONTROLCALLBACK;
}

//  CapControlCallback states
const CONTROLCALLBACK_PREROLL	= 1;
const CONTROLCALLBACK_CAPTURING	= 2;

extern (Windows) {
	HWND capCreateCaptureWindowA(LPCSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, int nID);
	BOOL capGetDriverDescriptionA(UINT wDriverIndex, LPSTR lpszName, int cbName, LPSTR lpszVer, int cbVer);
	HWND capCreateCaptureWindowW(LPCWSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, int nID);
	BOOL capGetDriverDescriptionW(UINT wDriverIndex, LPWSTR lpszName, int cbName, LPWSTR lpszVer, int cbVer);
}

version(Unicode) {
	alias capCreateCaptureWindowW	capCreateCaptureWindow;
	alias capGetDriverDescriptionW	capGetDriverDescription;
} else { // Unicode
	alias capCreateCaptureWindowA	capCreateCaptureWindow;
	alias capGetDriverDescriptionA	capGetDriverDescription;
}

// New Information chunk IDs
const infotypeDIGITIZATION_TIME	= mmioFOURCC!('I', 'D', 'I', 'T');
const infotypeSMPTE_TIME		= mmioFOURCC!('I', 'S', 'M', 'P');

// status and error callbacks
enum {
	IDS_CAP_BEGIN					= 300,
	IDS_CAP_END						= 301,

	IDS_CAP_INFO					= 401,
	IDS_CAP_OUTOFMEM				= 402,
	IDS_CAP_FILEEXISTS				= 403,
	IDS_CAP_ERRORPALOPEN			= 404,
	IDS_CAP_ERRORPALSAVE			= 405,
	IDS_CAP_ERRORDIBSAVE			= 406,
	IDS_CAP_DEFAVIEXT				= 407,
	IDS_CAP_DEFPALEXT				= 408,
	IDS_CAP_CANTOPEN				= 409,
	IDS_CAP_SEQ_MSGSTART			= 410,
	IDS_CAP_SEQ_MSGSTOP				= 411,

	IDS_CAP_VIDEDITERR				= 412,
	IDS_CAP_READONLYFILE			= 413,
	IDS_CAP_WRITEERROR				= 414,
	IDS_CAP_NODISKSPACE				= 415,
	IDS_CAP_SETFILESIZE				= 416,
	IDS_CAP_SAVEASPERCENT			= 417,

	IDS_CAP_DRIVER_ERROR			= 418,

	IDS_CAP_WAVE_OPEN_ERROR			= 419,
	IDS_CAP_WAVE_ALLOC_ERROR		= 420,
	IDS_CAP_WAVE_PREPARE_ERROR		= 421,
	IDS_CAP_WAVE_ADD_ERROR			= 422,
	IDS_CAP_WAVE_SIZE_ERROR			= 423,

	IDS_CAP_VIDEO_OPEN_ERROR		= 424,
	IDS_CAP_VIDEO_ALLOC_ERROR		= 425,
	IDS_CAP_VIDEO_PREPARE_ERROR		= 426,
	IDS_CAP_VIDEO_ADD_ERROR			= 427,
	IDS_CAP_VIDEO_SIZE_ERROR		= 428,

	IDS_CAP_FILE_OPEN_ERROR			= 429,
	IDS_CAP_FILE_WRITE_ERROR		= 430,
	IDS_CAP_RECORDING_ERROR			= 431,
	IDS_CAP_RECORDING_ERROR2		= 432,
	IDS_CAP_AVI_INIT_ERROR			= 433,
	IDS_CAP_NO_FRAME_CAP_ERROR		= 434,
	IDS_CAP_NO_PALETTE_WARN			= 435,
	IDS_CAP_MCI_CONTROL_ERROR		= 436,
	IDS_CAP_MCI_CANT_STEP_ERROR		= 437,
	IDS_CAP_NO_AUDIO_CAP_ERROR		= 438,
	IDS_CAP_AVI_DRAWDIB_ERROR		= 439,
	IDS_CAP_COMPRESSOR_ERROR		= 440,
	IDS_CAP_AUDIO_DROP_ERROR		= 441,
	IDS_CAP_AUDIO_DROP_COMPERROR	= 442,

	IDS_CAP_STAT_LIVE_MODE			= 500,
	IDS_CAP_STAT_OVERLAY_MODE		= 501,
	IDS_CAP_STAT_CAP_INIT			= 502,
	IDS_CAP_STAT_CAP_FINI			= 503,
	IDS_CAP_STAT_PALETTE_BUILD		= 504,
	IDS_CAP_STAT_OPTPAL_BUILD		= 505,
	IDS_CAP_STAT_I_FRAMES			= 506,
	IDS_CAP_STAT_L_FRAMES			= 507,
	IDS_CAP_STAT_CAP_L_FRAMES		= 508,
	IDS_CAP_STAT_CAP_AUDIO			= 509,
	IDS_CAP_STAT_VIDEOCURRENT		= 510,
	IDS_CAP_STAT_VIDEOAUDIO			= 511,
	IDS_CAP_STAT_VIDEOONLY			= 512,
	IDS_CAP_STAT_FRAMESDROPPED		= 513,
}

/**
 * FilePreview dialog.
 */

extern (Windows) {
	BOOL GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn);
	BOOL GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn);
	BOOL GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn);
	BOOL GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn);
}

version(Unicode) {
	alias GetOpenFileNamePreviewW	GetOpenFileNamePreview;
	alias GetSaveFileNamePreviewW	GetSaveFileNamePreview;
} else { // Unicode
	alias GetOpenFileNamePreviewA	GetOpenFileNamePreview;
	alias GetSaveFileNamePreviewA	GetSaveFileNamePreview;
}